Node.js, Mongoose, Express, Jade CRUD application

In this tutorial we will be looking at creating a CRUD application with Node.js, Express, Jade, MongoDB, Mongoose and Kendo UI.

Following are the sections that will be addressed:

1) Installing MongoDB and MongoVUE

a) Go to this link and follow the steps to download and install Mongo DB

http://docs.mongodb.org/manual/installation/

b) Once you have downloaded the milestone build of the mongo db, extract the same to say under c:\mongodb

c) Create a directory for Mongo DB data path such as c:\data\db

d) Start the Mongo DB now from the cmd prompt by hitting
   "mongod.exe --dbpath d:\test\mongodb\data"
e) You should be able to see waiting for connection message on the console.

f) To install the MongoVUE, go to this link and download the software http://www.mongovue.com/downloads/
g) Install the exe file and launch the application

h) Connect to your mongo server by entering the appropropriate name, Server, Port,username and password.

You have successfully completed the first part of the exercise.


2) Creating your express node application

a) Get started by creating an express project. Open cmd prompt and under your workspace hit - "Mongo_Node_CRUD". If you run into issues and need help with the set up of a express project, please read my previous post on getting started with express project here.

b) Test if the project runs on your local by running from cmd prompt and opening the same on the browser.


3) Say hello to Mongoose

a) Mongoose is an object modelling for node.js. Traverse to the Mongo_Node_CRUD dir, and under this project hit "npm install mongoose". This installs the latest version of mongoose on your project.

b) To get an in depth knowledge of the API and the commands please read the official API docs :
http://mongoosejs.com/index.html

c) We will be following the MVR pattern, under the route folder we have the index.js which is our router. We will employ this file to interact with our DB via mongoose. Further layer of abstraction is recommended when handling data from multiple DB's.

d) In the index.js we import the module installed followed by making the conncetion to the database:


var mongoose= require("mongoose");
//Connect to mongo DB
mongoose.connect('mongodb://' + "localhost" + '/mysystem');
var myDB = mongoose.connection;

//Error handling if conncetion fails
myDB.on('error', console.error.bind(console, 'connection error:'));
//Check if successful connection is made
myDB.once('open', function callback () {
  console.log("MY DB Connected with Mongoose");
});


4) Creating an employee schema

a) I would like to use a very common example of performing CRUD operation on an Employee object. For this purpose let us create the employee schema in the index.js as follows:


//create an employee schema for operation with mongo
employeeSchema = mongoose.Schema(
            {
    employeeid: String,
            name: String,
            address : String,
    created : Date,
    updated : Date
            },
            {
            collection:'employees'
            }
);

// model reference
employees = mongoose.model('employees', employeeSchema);


b) At this point on restarting and running the application and observing on the MongoVUE tool, you will see the following under collections:





5) CRUD operations on the employee using Mongoose

Now in the index.js let us continue to add the code for the create, read, update and delete operations using mongoose. The code is straight forward as shown below and more explanation can be obtained from the official mongoose API.

/**
*
*Create Employee
**/
function createEmployee(employeeid, name, address, callback)
{
            var objLog = new employees();
           
            objLog.employeeid = employeeid;
            objLog.name = name;
            objLog.address = address;
            objLog.created = new Date();
            objLog.updated = new Date();
             
            objLog.save(function (error, result) {
              callback(error, result);
            });
 }

/**
*
*Read Employees
**/
function readEmployees(callback)
{
            employees.find({},function (error, result) {
              callback(error, result);
            });
           
 }


/**
*
* Update Employee
**/
function updateEmployee(_id, name, address, callback)
{
            employees.findById(_id, function (err, item) {
              if (err){
                        callback(err, null);
              }
              else {
                        item.updated = new Date();
            item.name = name;
            item.address = address;
                        item.save(function (err, result) {
                          callback(err, result);
                        });
              }
            });
 }

/**
*
* Delete Employee
**/
function deleteEmployee(_id,callback)
{
            employees.findById(_id, function (err, item) {
              if (err){
                        callback(err, null);
              }
              else {
                        employees.remove(item,function (err, result) {
                          callback(err, result);
                        });
              }
            });
 }



Do not try to run the application yet at this point. We need to add some code to our UI to see this functional. So proceed to the next sections to add CRUD screens using Jade.

6) Creating the landing page in jade

In this part I am going to show how to create a template based UI with jade which is going to be inherited across all our CRUD screens.

In the layout.jade add the following code to the layout.jade:

doctype 5
html
            head
                        h1= "Node.js - Mongo DB - Mongoose - Jade - Kendo UI - CRUD Example"
                        link(rel='stylesheet', href='/stylesheets/style.css')
                        script(type='text/javascript', src='/jquery/js/jquery.min.js')
                        script(type='text/javascript', src='/kendo/src/js/kendo.web.js')
                        script(type='text/javascript', src='/kendo/src/js/kendo.grid.js')
                        link(rel='stylesheet', type='text/css', href='/kendo/src/styles/kendo.common.css')
                        link(rel='stylesheet', type='text/css', href='/kendo/src/styles/kendo.default.css')
                        p
                                    a(title='CREATE', href="/getCreateForm") Create Employee |
                                    a(title='READ', href="/readEmployees") Read Employees |
                                    a(title='UPDATE', href="/getUpdateForm") Update Employee |
                                    a(title='DELETE', href="/getDeleteForm") Delete Employee
            body
                        block content




You will see that in the above code we have added links to our create, read, update and delete forms to obtain the corresponding Jade UI.

Under the javascript folder you may also want to add the Kendo UI and Jquery library downloaded from the official sites. We will see the these in following sections.

7) Adding the routers

In the app.js let us create the routers for obtaing the CRUD UI and as well as the CRUD handlers for the operations with the DB.


/**
*
* Define the route handlers
**/
app.get('/', routes.index);
app.get('/getCreateForm', routes.getCreateForm);
app.get('/getUpdateForm', routes.getUpdateForm);
app.get('/getDeleteForm', routes.getDeleteForm);

app.post('/createEmployee', routes.createEmployee);
app.get('/readEmployees', routes.readEmployeesData);
app.get('/updateEmployee', routes.updateEmployee);
app.get('/deleteEmployee', routes.deleteEmployee);

app.get('/users', user.list);



8) Adding the route handlers

We will now add the router handlers to fetch the Jade CRUD UI's and as well as the route handlers for the CRUD operations in the index.js as follows:



exports.createEmployee = function(req, res){
            //console.log("data is ......"+req.body.employeeName);
            createEmployee(req.body.employeeId,req.body.employeeName,req.body.employeeAddress, function(error,result){
                        if (error) {
                res.send({'result':'error'});
        }else {                            
                                    console.info(" result:"+ JSON.stringify(result));
                                     readEmployeesData(req, res);
                }
            });
}

 function readEmployeesData(req, res){
            readEmployees(function(error,result){
                        if (error) {
                res.send({'result':'error'});
        }else {                            
                                    console.info(" result:"+ JSON.stringify(result));
                                     res.render('read',{title:'Reading from Mongo DB now ........',"result": JSON.stringify(result)});
                }
            });
}

exports.readEmployeesData = readEmployeesData;

exports.updateEmployee = function(req, res){
            updateEmployee(req.query['_id'],req.query['name'],req.query['address'], function(error,result){
                        if (error) {
                res.send({'result':'error'});
        }else {                            
                                    console.info(" result:"+ JSON.stringify(result));
                                     res.send('Data Updated');
                }
            });
}

exports.deleteEmployee = function(req, res){
            //console.log("in here.................."+req.query['_id']);
            deleteEmployee(req.query['_id'],function(error,result){
                        if (error) {
                res.send({'result':'error'});
        }else {                            
                                    console.info(" result:"+ JSON.stringify(result));
                                     res.send('Data Deleted');
                }
            });
}


exports.getCreateForm = function(req,res){
            res.render('createForm');

}

exports.getDeleteForm = function(req,res){
            readEmployees(function(error,result){
                        if (error) {
                res.send({'result':'error'});
        }else {                            
                                    //console.info(" result:"+ JSON.stringify(result));
                                     res.render('delete', { title: 'Deleting records',"result": JSON.stringify(result) });
                }
            });
}

exports.getUpdateForm = function(req,res){
            readEmployees(function(error,result){
                        if (error) {
                res.send({'result':'error'});
        }else {                            
                                    //console.info(" result:"+ JSON.stringify(result));
                                     res.render('update', { title: 'Updating records',"result": JSON.stringify(result) });
                }
             });
}

exports.index = function(req, res){
             res.render('layout', { title: 'Mongo-Node-Jade-CRUD Example' });
};


Under the views folder, do create place holder jade files that are empty for now calling them as create.jade, read.jade, update.jade and delete.jade. This will get rid of any compilation errors.

Save the files. Restart the application and you should see on launching the application the UI as follows:




We are almost done, just need to fill some flesh to our jade place holders.

9) Creating the forms for CRUD in jade.

a) The Create :

Please refer my post on creating a jade based create user interface here.

b) The Read:

Please refer my post on creating a jade based read user interface here.

c) The Update:

Please refer my post on creating a jade based update user interface here.

d) The Delete:

Please refer my post on creating a jade based delete user interface here.

10) Running the application

You can test the application now by
a) launching the create and creating a record.
b) launching the read and seeing the data created
c) launching the update and updating the data
d) deleting the created data

11) Summary of learning's

a) Creating a node.js application with mongoose
b) Creating template based UI with jade
c) Employing Kendo Grid for CRUD
d) Creating Schemas with mongoose
e) MVR model with Express.

12) The Voila Fix

It is often seen while working with Kendo UI that the cancel on the popup and the update sometimes do not work well and closes abruptly.

Here is the fix:

var dataSource = new kendo.data.DataSource({
pageSize: 6,
autoSync: true,
data: keyValuesResult,
schema: {
model: {
id:"employeeid",
fields: {
updated: { type: "date" },
created: { type: "date" },
address:{ type: "string" },
name:{ type: "string" },
employeeid:{ type: "string" },
_id:{type:"string"}
}
}
}
});


12 comments:

  1. So far this was the best tutorial on the subject, thanks for sharing.

    ReplyDelete
    Replies
    1. Thanks Bruno ... I am glad this blog helped you

      Delete
  2. Hi Naveen, a quick question. I see a lot of "callback" function int the callback function but don't see you pass in the callback function.
    For example,
    objLog.save(function (error, result) {
    callback(error, result);
    });
    Where is the "callback(error, result)" come from?

    Thanks,

    ReplyDelete
    Replies
    1. Hello,

      I am sorry for the delayed reply been busy with my sister's marriage preparations, however if it still helps -

      Please see in point 8 - Adding the route handlers, we pass the call back functions inline as the last parameters.

      Cheers,
      Naveen

      Delete
  3. thanks in advance, great tutorial :thumbup:

    ReplyDelete
    Replies
    1. Thanks. I am glad to see this docs. This is really very helpfull.

      Delete
  4. The article is good and the concept is very useful for everyone to enhance the skills.Waiting for your next updates.
    Node JS Online training
    Node JS training in Hyderabad

    ReplyDelete
  5. Valuable post useful for everyone.Keep on sharing.
    Mean Stack Online Training

    ReplyDelete
  6. This article is very much helpful and i hope this will be an useful information for the needed one.Keep on updating these kinds of informative things. Good information. Thanks for sharing with us.
    oracle training in chennai

    oracle training institute in chennai

    oracle training in bangalore

    oracle training in hyderabad

    oracle training

    oracle online training

    hadoop training in chennai

    hadoop training in bangalore





    ReplyDelete