Getting Started with MongoDB and Mongoose

In this post, we’ll show you how to use Mongoose for your MongoDB deployments to create a more straight-forward, schema-based solution to modeling your application data.

What is Mongoose?

Mongoose is an “elegant MongoDB object modeling for Node.js“. If you’ve used MongoDB before and tried basic database operations, you might have noticed that MongoDB is  “schema-less”. When you’re looking to implement a more structured database and want to leverage the power of MongoDB, Mongoose is one of the ODM (Object Data Mapping) solutions.

To quickly demonstrate, you run an insert command into a collection named users like this:


db.users.insert({ name : 'Arvind', gender : 'male'});

And right after that, you can run:


db.users.insert({ name : 'Arvind', gender : 'male', password : '!@#$'});

and MongoDB will never complain about the variation in the number of columns (key-value pairs). This is very flexible. But when you want to keep your data more organized and structured, you would need to maintain that in your server code, writing validation, making sure nothing irrelevant is stored in a collection. This is where Mongoose makes life easy.

“Mongoose provides a straight-forward, schema-based solution to modeling your application data and includes built-in typecasting, validation, query building, business logic hooks and more, out of the box.”

Install Node.js & MongoDB

To use Mongoose, we need to have Node.js installed. You can find info here.

Start Developing

First, let’s create a small playground where we can have fun. Create a new folder named myMongooseApp and open terminal/prompt here and run:

npm init

This will help us in initializing a new node project. Fill it up as required. Next, we’ll install Mongoose as a dependency to our project. Run:

npm install mongoose --save-dev

Then, start the MongoDB service by running:

mongod

Next, create a new file named index.js at the root and then open it up in your favorite editor. Add the below code:

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/myTestDB');

var db = mongoose.connection;

db.on('error', function (err) {
console.log('connection error', err);
});
db.once('open', function () {
console.log('connected.');
});

Here, we require the Mongoose package to connect to the database and initialize the connection. The name of our database is myTestDB.

Then, run:

node index.js

You should now see the connected message. You can also use a node package named nodemon for automatically restarting the node server on changes.

Now, our sandbox is ready to play!

Mongoose Schemas

Schemas are like skeletons, the bare bones of how your data collection will look. If you’re dealing with a collection of users, your schema would look something like this:

Name - String
Age - Number
Gender - String
Date of Birth - Date

If you are dealing with a collection of products, your schema will look something like this:

SKU - String
Name - String
Price - Number
InStock - Boolean
Quantity - Number

You can see the drift. When our data is guarded with a schema like this, the possibility of storing garbage data reduces drastically.

Now that we’ve got an understanding of schemas, let’s try and build a user schema using Mongoose. Back to index.js and add the below code:

var Schema = mongoose.Schema;
var userSchema = new Schema({
name : String,
age : Number,
DOB : Date,
isAlive : Boolean
});

Find basic user-related fields and their schema types here.

Next, we’ll create a model from the schema. Add:

var User = mongoose.model('User', userSchema);

That’s it, our user model is ready! We’ll use this as our base schema to insert users into the database. This way, we know that every document in a user collection will have the fields listed on the schema. Let’s create a new user instance and save it to DB. Add:

var arvind = new User({
name : 'Arvind',
age : 99,
DOB : '01/01/1915',
isAlive : true
});

arvind.save(function (err, data) {
if (err) console.log(err);
else console.log('Saved : ', data );
});

You should see something like this:

Saved : { __v: 0,
name: 'Arvind',
age: 99,
DOB: Fri Jan 01 1915 00:00:00 GMT+0530 (IST),
isAlive: true,
_id: 536a4866dba434390d728216 }

No hassles, no issues. Simple and easy API to interact with Models.

Let’s say that we want each model to have a method named isYounger. This method will return true if age is less than 50, and false if greater. We can do this by querying the database for the current user, then checking the conditioning and the returning true or false.

But what if we want to implement this method to all the models of User schema? This is how we do it in Mongoose:

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/myTestDB');

var db = mongoose.connection;

db.on('error', function (err) {
console.log('connection error', err);
});
db.once('open', function () {
console.log('connected.');
});

var Schema = mongoose.Schema;
var userSchema = new Schema({
name : String,
age : Number,
DOB : Date,
isAlive : Boolean
});

userSchema.methods.isYounger = function () {
return this.model('User').age < 50 ? true : false;
}

var User = mongoose.model('User', userSchema);

var arvind = new User({
name : 'Arvind',
age : 99,
DOB : '01/01/1915',
isAlive : true
});

arvind.save(function (err, data) {
if (err) console.log(err);
else console.log('Saved ', data );
});

console.log('isYounger : ',arvind.isYounger());

On line 21, we add the method definition, and the result on line 39 will be false. This is a simple, handy way of adding methods to your schema, making it more object-oriented-ish.

In case you have a password field, you can add a method like encryptPassword(), to encrypt password and comparePassword(), to compare the passwords at login to the userSchema itself. You can read more about password Authentication here.

Out-of-the-box Mongoose also provides a few options when the schema is created. For example, if you take a look at the below schema declaration, we’re passing an option strict:false:

var userSchema = new Schema({
name : String,
age : Number,
DOB : Date,
isAlive : Boolean
}, {strict : false});

The strict option is true by default and it does not allow the ‘non-schema’ key-value pairs to be saved.  For example, this will be saved:

var arvind = new User({
name : 'Arvind',
age : 99,
DOB : '01/01/1915',
isAlive : true
});

Whereas:

var arvind = new User({
name : 'Arvind',
age : 99,
DOB : '01/01/1915',
isAlive : true,
bucketList : [{...}, {...}, {...} ]
});

All of the above will be saved minus the bucketList array because it was not declared as part of the schema. So, no client who consumes your services will be able to dump invalid data into your collections.

Another cool option is the collection. If you don’t want your model name to be the same as collection name, you can pass the name as an option like:

var userSchema = new Schema({
name : String,
age : Number,
DOB : Date,
isAlive : Boolean
}, {collection : 'appusers'});

You can find a list of other options here.

With Mongoose, You can also add events to your schemas like pre-save or post save, where you can perform validations, process data or run other queries in the respective events. These methods are called as Middlewares.

A simple example can be a parallel middleware like:

var userSchema = new Schema({
name : String,
age : Number,
DOB : Date,
isAlive : Boolean
})
schema.pre('save', true, function (next, done) {
// calling next kicks off the next middleware in parallel
next();
doAsync(done);
});

You can read more about middlewares here. In our next post, we’ll talk more about using Yeoman to automatically generate scaffolding for your MongoDB projects.

Thanks for reading. Do comment.
@arvindr21


Arvind Ravulavaru is a passionate web developer, likes experimenting with new and upcoming technologies. He also blogs at http://thejackalofjavascript.com


  • Pingback: Yeoman, Mongoose & MongoDB()

  • Aldo Escobar

    Thank you!

  • jay

    i could not insert the data. please help….this is the code snippet i use….

    var user = new User;
    user.massAssign({
    name : req.body.name,
    email : req.body.email,
    number : req.body.number,
    prority: “low”
    });

    user.pre(‘save’, true, function (next, done) {
    next();
    doAsync(done);
    });

    neither does User.create(user); work for me

  • prashanth R

    date compare in moongose is not working any reason ?

  • Edouard BERTHE

    Hi,

    Thank you very much for that ! I’m coming from Python Flask and PHP Symfony, and am a great fan of SQL databases. I’m learning Meteor with MongoDB, and despite all my open-mindedness I have a lot of difficulties with no Objected Oriented at all… this will solve my problem thank you :)

  • jean

    Indent your FUCKING code please :3

4 Shares
+11
Tweet
Share1
Share1
Pin1