Why do we import Mongoose in the Express server file? - node.js

I have a Node/Express app that uses Mongoose to talk to a MongoDB database. The Express server is configured in a file called server.js and the schema is in a separate models.js file. Following every project and tutorial I've seen so far, I have the mongoose.connect() configured in both places:
// server.js
const express = require('express');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const app = express();
mongoose.connect('mongodb://127.0.0.1/mydb');
// models.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const User = new Schema({
username: String,
password: { type: String, select: false },
name: String,
});
module.exports = mongoose.model('User', User);
My question is, since I'm already importing mongoose in models.js, can I not skip doing so in server.js entirely and just set the connection in the model script itself? What's the point of importing it and configuring a connection along with the rest of the server config when I'm only going to use it when working with the schema? And If the answer is yes, why doesn't anyone do that? Is there a performance benefit at play here?

You could do mongoose.connect() in your model script but this would not be advisable.
You would have to ensure that this model was loaded before any other scripts that required the mongoose connection.
If you go on to create another model in your application, then this would rely on your User model (model.js) having been loaded first.
You would have to perform the connection in each model just to be sure, but this would be a poor design and unnecessary code duplication.
Therefore, connecting in server.js is the best approach to ensure the connection is established as early as possible.

It is not necessary that you require the mongoose in the server.js file. In fact in my project I create a separate file for each connection like connection_one.js, connection_two.js and export the mongoose object. This way when any number of models does a require("./connection_one.js") it will return the same connection ready mongoose for all models exporting it. This is possible due to modules are cached on first time load inside a project. It is what is also happening when you are loading the mongoose module in server.js, it is the same mongoose object in server.js and model.js.

To address you question, first of all you need to understand object-oriented programming. Right now, you have two different files. One if server.js. and another is models.js. And each file has it's own scope.
Even if you imported mongoose in server.js since the two scopes has different scope set, models.js cannot utilize the mongoose service imported in server.js. For example, let say you defined a variable "foo",
You cannot use that variable in model.js because their scopes are isolated.
// server.js
const foo = 'bar';
If you want to use only one mongoose imported in a single script and shared by others, you can use global object from Node.js env. Check out the url to know more about this.
node.js global variables?
However, I don't really recommned putting mongoose service in gloabl object. Global scope can be easy at the beginning, but it could be significant scalability problem as your application grows bigger in later time.
Thanks.

Related

How can two different Node.js servers communicate to one mongoose schema?

I have two servers (Public server and Admin Server) and I would like to access from both one mongoose schema. The main server is the Public one where everything happens, but sometimes, from Admin server I would like to access that schema. I could write the schema on both the servers, but that would mean bad code. If that is the only solution, I will do it. But, is there any other way of doing this? For MongoDB I have a third server, that is only for database. Could I write something there so that when I connect with mongoose to the MongoDB server to receive the model from there?
Let's say I have this code (somewhere, I don't know where yet).
const mongoose = require('mongoose');
const postSchema = mongoose.Schema({
title: {
type: String,
required: true,
}
});
const Post = new mongoose.model('Post', postSchema);
module.exports = Post;
What I am trying to do in a server file is for example to call Post.save() or whatever function I am trying to get, without having the schema on both servers.
I used Mongoose-Gen npm and created an API in order to get the schema from on server to another.

how to use passport.js local strategy without creating a schema,or database model

I was trying to understand how to use the passport.js in Mongodb native driver,Express now the problem is that all the reference or tutorials are showing the LOCAL-STRATEGY by using mongoose which creates a schema or model........so now iam STUCK
Take a look at the mongodb documentation for their Nodejs driver.
mongoDB Node Driver
Sorry for being here for a little bit late, but maybe my answer would be helpful to others who seeking answer for this kind of question.
I assume that you were struggling with these problems:
How to reuse database connection among your project
You can define your MongoClient object once and reuse this across multiple modules in your project as follow:
dbUtil.js hold definition of MongoClient object:
const MongoClient = require('mongodb').MongoClient;
const SERVER_URI = // link to your server, for example: 'http://localhost:27017';
const DB_NAME = // database name, for example: 'test';
/* #WHY?:
(option 1?) : to let the server assign objectId instead of Node driver,
(option 2 & 3?) : to get rid of deprecation warnings
*/
const clientObj = new MongoClient(`${SERVER_URI}/${DB_NAME}`, {
forceServerObjectId: true,
useNewUrlParser: true,
useUnifiedTopology: true
});
module.exports = {
client: clientObj,
dbName: DB_NAME
}
In another module where you need to use the defined connection:
const { client, dbName } = require('dbUtil');
// Because client.connect() return a Promise, you should wrap everything
// inside an immediately-invoked expression like this
(async () => {
await client.connect(); // at first you need to open the connection client
const dbO = await client.db(dbName); // get the connection to database
/* perform database operations, for example:
dbO.collection(users).insertOne({ name:'mongoadmin' });
*/
client.close(); // remember to close the connection when you're done
})();
So instead of the Mongoose way of using User.find().exec(), in Mongo native driver you have to activate connection to Client first and then use client.dbO.collection('users') (which return a Promise).
What the heck is Passport and why it's needed for your project
Passport is authentication middleware for Express that support authentication from Facebook, Google, JWT,... and many other authentication strategies. It can be helpful when you need to you want to support authentication from multiple authentication portal. However, it's not a must-have.
Sometimes applying another layer of abstraction from third-party libraries not only bring no sense to you & your project, but also over-complicate your existed code base. You'd chose not to use Mongoose and adapted MongoDb native driver instead, stated that you didn't need schema & model stuffs. For the same logic, I don't see any necessity of adapting Passport. This link can be helpful to you in some way: another Stackoverflow post
To apply authentication using JSON web token to your Express routes, you need to do these following steps:
Generate token for user signed in
Verify token
Define protected routes and write middlewares for those
All these tasks can be done without any third-party modules/libraries!
I believe your question stems from using mongodb schema validation instead of mongoose schema. You can use another means of authentication like JWT which does not directly need models for its authentication.

How to use MongoDB with mean.io

I am new to server side javascipt. I have started with mean.io. I gained some understanding of nodejs, express, mongodb last few days. I have my mean.io app but I don't know what's the right way to connect to mongodb and query it from my js files.
Is there a guide/blog which can help me work with mongodb from my server side javascript files?
All I want is to store some data mongodb and fetch that at some later point.
By default, you should see there is a mean-dev collection in your mongodb. The best way I thought to get familiar with mongo and mean is play around the code (for instance, the article package). Inside /packages/article/system/, you will see how the blog example works.
That works great for me.
I couldn't find one related to mean.io but below few links helped me get started with mean.io.
http://cwbuecheler.com/web/tutorials/2013/node-express-mongo/
https://www.youtube.com/watch?v=AEE7DY2AYvI
https://www.youtube.com/watch?v=5e1NEdfs4is
Edit:
Past few days I have been working on it and by test & learn I was able to got things working for me. I'll share whatever I know till now.
So mean.io use mongoose ODM to connect to the mongodb.
mean.io would automatically connect to your DB. You can configure DB name in development.js db: 'mongodb://localhost/myDB'. So you won't have to worry about connecting to mongoDB. You just need to start the mongoDB using mongod.
How to use mongoose?
To use mongoose to connect to mongoDB you need to build schemas. You can do so in myApp/app/models directory, since they represents models.
Sample model file user.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
name: String,
email: String,
DOB : Date,
address: {
house_no: String,
street: String
}
});
module.exports = mongoose.model('tbl_user',userSchema);
Note:- tbl_user would be stored as tbl_userS in DB.
How to save data to mongoDB?
One would generally do save to DB in controller. Below I have shown how one can do this.
To make models available to all controller one need to write this piece of code in server.js so that all your models get registered during server startup. Alternatively, import individual models using require('tbl_user').
Server.js :-
var models_path = __dirname + '/app/models';
var arrFiles = fs.readdirSync(models_path);
arrFiles.forEach(function(file){
if(file.indexOf('.js') > 0){
require(models_path + '/' + file);
}
});
controller code myApp/app/controllers/myController.js
var mongoose = require('mongoose');
var jsonEntry = {'name':'Mady', 'email':'xyz#xyz.com', 'address':{'house_no':12N, 'stree':'abc'}};
var User = mongoose.model('tbl_user');
var user = new User(jsonEntry);
user.save();
The above code would create and update the tbl_users collection in mongoDB.

Are the variables defined in app.js accessible to the functions in routes, in Express and node js?

I was coding using express js, and I noticed that I declared this in app.js
var mongoose = require ('mongoose');
var db =mongoose.connect('mongodb://localhost/testdb');
Then in my /models/userSchema.js
var mongoose = require('mongoose');
var users = mongoose.model('users',UserSchema);
module.exports = users;
However in my routes/upload.js
var mongoose = require ('mongoose');
var db =mongoose.connect('mongodb://localhost/testdb');`
//some code
mongoose.model('users').find();
// This knows that i am accessing the database called "testdb"
I am not sure why this works like how the code executing in upload.js and userSchema.js knows that the database i am using is testdb. Isn't this declaration of var mongoose = require('mongoose'); creates a new object separate from the one in app.js?
In node.js, modules loaded with require are cached so that calling require('mongoose') in two different files returns the same instance of the mongoose module.
So while variables from one file are not directly accessible in other files, variables within the same module are effectively shared between the files that require that module.
Mongoose is singleton. That is when you require it again you get the instance you first initialized.
App level variables are not visible in other modules. There are ways to pass the app object I tide modules though.

How do I properly lay out Mongoose in an Express project?

I created my Schema's in my models/mymodel.js file. I also have my models in there as well as my methods.
How do I export them into my routes?
// route.js
var mongoose = require("mongoose");
var Posts = mongoose.model("posts")
...
Ensure that you set up a bootstrap mechanism that runs all your model files. Once that is done you should have called mongoose.model("name", Model) for a set of models.
This has cached those models in mongoose internally. So you can just call mongoose.model("name") anywhere you want.
The only thing that's important is order of execution. The model & schemas need to be registered before you run your routes.
This is as a simple as :
// create app
var app = express.createServer(...);
// do stuff with app
var files = fs.readdirSync("models");
files.forEach(function(file) {
require("models/" + file);
});
var routes = fs.readdirSync("routes");
routes.forEach(function(route) {
require("routes/" + route)(app);
});
app.listen(80);
Note that normally readdirSync is evil but it's ok to execute blocking calls at startup time (like require) before your listen to your server
Mongoose creates a singleton when you require() it, and subsequent calls return the same instance.
So as long as you require mongoose when your app inits, then define your models, they will be available in any other file where you require mongoose as described by Raynos.
Unless you want to manage connections to the db server manually, it's also a good idea to call mongoose.connect('...') in your app init; the connection will persist across requests.

Resources