Built.io Blog

Let's play with Mongoose

,

NOTE: This blog is a continuation of a previous post, Express your business logic in node using MongoDB. We recommend reading the previous post first if you have not done so already.

In the previous post we covered how to interact with MongoDB in a Node.js application using Express. In this post, we will use Mongoose Object Relation Mapping (ORM) to achieve the same thing.

What is ORM ?

For computers, software is a programming technique that converts data between incompatible systems in object-oriented programming languages.

This creates, in effect, a "virtual object database" that can be used from within the programming language. There are both free and commercial packages available that perform object-relational mapping, although some programmers opt to create their own ORM tools.

What does mongoose do?

mongoose is an object relation mapping tool that provides a straight-forward, schema-based solution for modeling your application data that includes built-in type casting, validation, query building, business logic hooks, and more.

The first task is to add mongoose to the app, and there are two ways to do this:

  1. Add entry in package.json like this
    {
      "name": "application-name",
      "version": "0.0.1",
      "private": true,
      "scripts": {
        "start": "node app.js"
      },
      "dependencies": {
        "express": "3.4.6",
        "jade": "*",
        "mongodb": "*",
        "monk": "*",
        <strong>"mongoose","*"</strong>
      }
     }   
    
    	
    Now run:
      C:nodetestapp && npm install
    	
    This will install mongoose and its dependencies.
  2. Go to the app directory (C:nodetestapp)and install the Mongoose module using npm:
     npm install mongoose

This will also install mongoose and its dependencies.

The first task, after installing Mongoose, is to create a connection string so that a database connection is available, allowing us to establish a connection at our app entry point (i.e.: in app.js).

Add require mongoose to the top of app.js to add the module to the app:

mongoose = require('mongoose');

Add the following code:

app.use(function(req,res,next) {
  mongoose.connect("mongodb://localhost/testapp");
  var db = Mongoose.connection;
  db.on('error', console.error.bind(console, 'connection error:'));
  db.once('open', function callback () {
    console.log('DB initialised successfully');
    app.locals.db = db;
  });
  next();
});

When we restart our server, we should get this message: DB initialised successfully in the console or log, because we added console.log('DB initialised successfully'); in the function when the connection was created. As soon as we get this output, we are ready to use our database.

We will continue by developing user model to add more structure.

mkdir model

Add the User.js file in this directory, so that User.js will be our user model.

Let's define our user model schema. Oh wait, we are using MongoDB which is schema-less, so is it necessary to define schema? The answer is YES.

Everything in Mongoose starts with a schema. Each schema maps to a MongoDB collection and defines the shape of the documents within that collection.

Let's add the following code in the User.js model:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

Define your schema

var userSchema = new Schema({
  username:   {type: String},
  email:      {type: String},
  firstname:  {type: String},
  lastname:   {type: String}
});

Create a model

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

That's it; our user model is now ready to use.

Let's update our view for two new extra fields.

Go to views/new_user.jade and update or replace the existing code with the following code:

extends layout
block content
    h1= title
    form#formAddUser(name="add_user",method="post",action="/users")
        input#inputUserName(type="text", placeholder="username", name="username")
        input#inputUserEmail(type="text", placeholder="useremail", name="useremail")
        input#inputFirstName(type="text", placeholder="firstname", name="firstname")
        input#inputLastName(type="text", placeholder="lastname", name="lastname")
        button#btnSubmit(type="submit") submit

First, we will try to store the database record. To store the record, we need to require this model at routes/user.js:

var UserModel = require('./model/User');

Remember, we added the add_user POST method to add a user record, so let's update this function to work with Mongoose.

exports.add_user = function(req, res){
// Get our form values. These rely on the "name" attributes
var userName  = req.body.username;
var userEmail = req.body.useremail;
var firstName = req.body.firstname;
var lastName  = req.body.lastname;
// Submit to the DB
var user = new UserModel({
    "username" : userName,
    "email" :    userEmail,
    "firstname": firstName,
    "lastname":  lastName     
});
user.save(function (err, doc) {
      if (err) {
        // If it failed, return error
        res.send("There was a problem adding the information to the database.");
      }
      else {
        // If it worked, redirect to root url      
        res.redirect("/");
      }
    });  
}

Now we will update listUser action to fetch all users from db.

exports.list =  function(req, res){      
    UserModel.find().exec(function(err,docs){        
      res.render('list_user', {
        "userlist" : docs,
    "error": err
      });
    });  
}

that's it we have added record in to the db and fetched the records from the db using mongoose as ORM.

mongoose is very powerful, provides lots of features. We will see "Virtuals" feature provide by mongoose.

Virtuals

Virtuals are document properties that you can get and set but that do not get persisted to MongoDB.

The getters are useful for formatting or combining fields, while settings are useful for de-composing a single value into multiple values for storage.

var user = new UserModel({
  "username" :     "harshal",
  "email" :     "harshal.joshi@raweng.com",
  "firstname":    "Harshal",
  "lastname":     "Joshi"      
});

Suppose we have user object and we want to log the full name of user. We could do this manually like so:

console.log(user.firstname + ' ' + user.lastname);

Or we could define a virtual property getter on our userSchema so we don't need to write out this string concatenation mess each time:

userSchema.virtual('fullname').get(function () {
  return this.firstname + ' ' + this.lastname;
});

So when we access

user.fullname
we should get Harshal Joshi as output.

To know more how powerful mongoose is? just visit their official site

My favorite is population feature provided by mongoose. It's just awesome if we want implement relational db architecture in schema less db.

Where to go from here? just visit mongoose site get familiar with awesome features provided by them. I am damn sure you will love it.

Subscribe to our blog