Difference between require('mongoose').Mongoose and require('mongoose') - node.js

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

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.

Best practices for mongoose with multiple identically structured databases

I have a Node.js project dealing with multiple customers. For several reasons, mainly separation of concerns, security, and partial transferability, I have to put every customer's data into a separate Mongo database. All databases store the same object types and thus have the same set of collections with identical structure. I have already found many technical solutions to solve that issue, but my question is more concerned with the best practices handling this situation. A simplified view into my code (omitting the boilerplate code to create a server, module structure, etc.):
const mongoose = require('mongoose');
// Customer codes act as DB names, actually comes from config file or DB
let customers = ['c1', 'c2'];
// keeps all mongoose connections
let conns = {};
// create a connection(pool) for each DB
for (let i in customers) {
let dbname = customers[i];
conns[dbname] = mongoose.createConnection(`mongodb://${host}:${port}/${dbname}`);
}
// a simple Schema for blog articles
const ArticleSchema = new mongoose.Schema({
title: String,
text: String
});
// keeps all Article models
let Article = {};
// create the identical models for the different DBs
// remember: the dbname is the unique customer's code
for (let dbname in conns) {
let conn = conns[dbname];
Article[dbname] = conn.model('Article', ArticleSchema);
}
const app = require('express');
// returns all articles of a certain customer
app.get('/customers/:customerid/articles', function(req, res) {
// get the customer's code from the URL
let dbname = req.params.customerid;
// Query the database
Article[dbname].find({}, function(err, articles) {
if (err) return res.status(500).send('DB error');
res.status(200).send(articles);
});
});
This code works. Nonetheless, I wonder, if there ist a best practice I am not aware of to handle this kind of requirement. Especially, it feels strange to keep the connections and models in maps and to access the objects with the dbname in square brackets. Please keep in mind that this is an extremely simplified version. In the real version the code is distributed across several modules handling different object types etc.
Note: A simple mongoose.connection.useDb(dbName) to switch to a different database doesn't work since the model has to be registered with respect to the connection, which itself must be bound to a database (as far as I understand it).
Update: Handling every customer with a single node process and setting up a proxy switching to those processes with respect to the customer - as suggested in the question mentioned by Paul - is currently not an option due to the administrative effort necessary to set things up in our current environment. We have to launch the service quickly right now.

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.

Can't seem to display data from mongolab using node.js

i'm been trying to display just a simple data from mongolab to nodejs and it displays nothing for some reason.
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
mongoose.connect("mongodb://db-user:pass#ds049084.mongolab.com:49084/mydb");
mongoose.model('collection',{ name:String });
router.get('/', function(req, res, next) {
mongoose.model('collection').find({},function(err,docs){
res.send(docs);
});
});
I've already saved a name data in the document of the collection in mongolab, the only it shows when i run the debug script
debug=mynode:* npm start is []
does anybody know why is that? thank you.
Fixed it!, man..the problem is the way i named the collections at mongolab. I was missing the "s" at the end of collection. Once i deleted the collection and created another but this time the "s" at the end, then it worked.
e.g.
Naming a collection 'Car' will not work but naming it 'cars' will work somehow
I can't comment yet because of my rep...
But to elaborate.. The reason why you need the "s" at the end is because when you do:
mongoose.model('<the schema you want to map to in your db>',<yourschema>);
"Mongoose automatically looks for the plural version of your model name" in your db.. as it says in the Mongoose documentation.. hence if you type myDbSchema it would look for myDbSchemas (Note the "s") and so thats why in your mongolabs Db the schema would need the extra "s"... confused me for a bit to but I hope this can help someone! :) as this post did help me too.
FYI Mongoose documentation: Mongoose Models Doc

Inject unique mongoose instance in module

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"

Resources