Inject unique mongoose instance in module - node.js

My modules get a mongoose instance injected but now they all use the database that was set on the last mongoose.
For example my main module creates a lot of modules and then calls init on them.
var mongoose = require('mongoose');
//...
mongoose.connect(connString);//specific to finance
var finance = require('finance').init({db:mongoose});
Before I injected the mongoose instance the finance module required mongoose by itself and since it's in the node_modules it gets it's own mongoose. Now; no matter how many main modules I make and how many times I call require it'll always get the instance it got the first time.
Therefor all modules created will be connected to whatever is set by the last connect.
It is possible to use createConnection but still not sure how to inject mongoose, I tried:
var mongoose = require('mongoose');
//...
var c = mongoose.createConnection(connString);//specific to finance
mongoose.connection=c;
var finance = require('finance').init({db:mongoose});
Now I get an error like Cannot overwritefinancemodel once compiled.
Somehow it's very hard to get another instance of mongoose in the same module. This is funny because according to mongoose you should be able to use different connections for different models but since you need a mongoose instance to define a model then how do you inject it? Require keeps returning the same instance over and over again.
Tried the following but both didn't work.
console.log('deleting mongoose cache:',require.cache.mongoose=undefined);
//or this one
console.log('deleting mongoose cache:',delete require.cache.mongoose);
So the question is: how do I inject mongoose in my modules that have models that require a unique database? If main sets up the mongoose instance and connection to inject into the model then how do I prevent it from creating the same one over and over again?
If it's possible to create unique connections with createConnection then what do I inject into the modules? With this connection I can't create models, need a mongoose instance for that. If each model needs to invoke require to get it then mongoose is un injectable.

So mongoose uses a singleton pattern. When you do require("mongoose") you are getting the same instance of a constructor each time as seen at the bottom of mongoose/lib/index.js (source code link here). var mongoose = module.exports = exports = new Mongoose;
To get unique instances, use this pattern:
var singleton = require("mongoose")
var unique = new singleton.constructor();
//now use "unique" just as you would "mongoose"

Related

Generate Mongoose ObjectId in NextJs Frontend

I am trying to generate Mongoose compliant ObjectId's on a NextJs frontend. The thing is though, the minute you import mongoose to try use the good-ol' const ObjectId = mongoose.Types.ObjectId; then const _id = new ObjectId(); 'maneuver' it immediately throws a TypeError: t.versions.node is undefined error in my case (very hard to debug the first time.. I was optimist it would work maybe this time doing some refactoring a few months later... But the minute I tried like oil in water.).
import mongoose from 'mongoose';
// and
const mongoose = require('mongoose');
Give the same error.
Is there a better way to create it? Other systems rely on this being a valid Id i.e. not just the same alphaNumeric length.
Less of a performance hit than creating a NextJs API GET route that just returns my backend shenanigans as a simple string (a network request?).
P.S. Use TypeScript if that could mean anything.. Also using Vercel (which has also caused build problems in the past)
I was too stuck in looking for a NextJs solution in my searches when it is still Javascript and React at the end of the day. This thread had the answer:
npm i bson
then
import { ObjectID } from 'bson';
const id = new ObjectID();
Works perfectly in NextJs as well as my Mongo/Mongoose database.

Where data will be stored in Mongo DB by default, when we use mongoose with Express

I am new to Node JS technology. I have 3 basic doubts.
In my nodeJS application, I connected to mongodb using mongoose. But I did not mention any collection name. But data is getting saved when I sent data from Form as expected. I want to know that in which collection it will be stored by default. How to see the stored data.
how to mention specific collection name using mongoose if we want to save data in a particular collection.
3.Generally If we want to use any middleware in our app, we connect that
middleware using app.use() right? but in mongoose case, we do not add that
to app.use(). but still we can use the mongoose functionality.
could anyone please tell how it is possible.
Thanks a lot in advance.
How Mongoose interacts with MongoDB is described here.
It has this example:
var schema = new mongoose.Schema({ name: 'string', size: 'string' });
var Tank = mongoose.model('Tank', schema);
and mentions that
The first argument is the singular name of the collection your model is for. Mongoose automatically looks for the plural version of your model name. Thus, for the example above, the model Tank is for the tanks collection in the database.
model() takes a third argument where you can rename the collection:
var Tank = mongoose.model('Tank', schema, 'collectionname');
The collection gets made when model() is called.
app.use() is used for Express middleware. Mongoose isn't really that, which is why you're not using app.use() in this case.
This should probably be broken into multiple questions and you should probably show some code. That said, I'll take a crack at it.
Collection names are defined when you model your schema. So let's say you have:
const UserSchema = new Schema({
name: String
});
And then you later will tell mongoose to model it:
mongoose.model('User', UserSchema);
You'll have a collection called "users" in the database you're connecting to in your mongoose.connect() call.
Regarding middleware, Express middleware is specifically functions that you want to fire during the request/response cycle. You can still call code (e.g. mongoose) outside that cycle, and generally you'll connect to the database when the application starts and then read or save to it in either middleware or in your route handlers. For example, you might have a route like:
const User = mongoose.model('User');
app.get('/users', (req, res, next) => {
User.find({}, (err, users) => {
if (err) return next(err);
res.send(users);
});
});
In that case, you've got a route handler that calls mongoose through the User model previously defined.

Add a method to Express model

Let's suppose I have an Express model:
var SchemaDescription = {};
var Model = = new mongoose.Schema(SchemaDescription);
Express allows to tune up data validation in SchemaDescription. On save it works perfectly, but on update, because of mongoose nature, it isn't called, and there is no clean way to call it.
I tried Model.pre('update', ...); but didn't found the way to access/correct model's data before writing to the DB: because complex validation logics, which, for example, re-formats some data before checking.
A logical solution is to put validation code to save/update controller's handlers, but it leads to duplication of the code. To keep MVC pattern as for save, as for update, I'd like to put a public method to the model, or the schema, which gets input data and validate them.
My attempts look like:
Model.prototype.validate = function(input, isUpdate) {...};
or
SchemaDescription.validate = function(...) {...};
in different combinations.
The response always looks like "Cannot set property 'validate' of undefined"
Is there an approach to put a custom public function-member to an Express model/schema for being called in controllers?
What approach may be used to validate data on save and update, without code duplication, or/and putting validation logics to controllers?
You don't have an Express model, you have a Mongoose model. According to the latest documentation, you can explicitly activate validation on update: http://mongoosejs.com/docs/validation.html#update-validators

Difference between require('mongoose').Mongoose and require('mongoose')

I've noticed that certain libraries like
Mockgoose (https://github.com/mccormicka/Mockgoose/blob/master/test/index.spec.js)
use require('mongoose').Mongoose to declare an instance of mongoose like this:
var Mongoose = require('mongoose').Mongoose;
var mongoose = new Mongoose();
var db = mongoose.connect('mongodb://localhost:27017/TestingDB');
However, most examples I've seen online does this to connect to a database:
var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost:27017/TestingDB');
I just want to know if there's a difference between these two methods of getting an instance of mongoose or are they really two different ways to get the same thing.
Thanks
There is a difference between the two.
require('mongoose') returns an instance of Mongoose, and new require('mongoose').Mongoose gives you a new instance of Mongoose that isn't the same instance as the one returned from require('mongoose'). The latter is useful when a particular part of your app needs it's own instance of mongoose that doesn't conflict with the rest (which makes it perfect for unit testing)
In a typical application though you'll want to simply use require('mongoose') so that everywhere you use require('mongoose'), you'll get the same instance.
https://github.com/Automattic/mongoose/blob/master/lib/index.js#L520

Mongoose connection/models: Need to always run on open?

I am using Mongoose 3 and the most obvious way to connect to database is
conn = mongoose.createConnection(...)
conn.on("open", ...)
Question is, do I need to define all my models in the open callback? If that is so, I will have to create a initMongoose.coffee that looks like
# initMongoose.coffee
mongoose = require "mongoose"
module.exports = mongoose.createConnection ...
# modelExample.coffee
conn = require "./initDatabase"
conn.on "open", ->
... define model?
modeule.exports = model # I think this does not work?
I think I read somewhere in Node docs that modules cannot be defined in a callback like that?
Since I am only using 1 connection, I think I can use
mongoose.connect ...
Which doesnt accepts any callbacks so I suppose is synchronous? Can I define all my models and thus queries right after connect()? It works at the moment, but it might be because its fast enough.
Mongoose buffers up commands until it is finished connecting, so you can treat it like it's synchronous and define your models and start using the library whenever you want; only once you want to start actually inserting or retrieving data do you need to make the connection.

Resources