Key points for me to refer to when I need to create node.js applications

I had decided to include node.js into my toolbox. In the process of getting myself acquainted with node.js, I had jotted down some key points for myself for developing node.js applications in the future. This posts list those key points, and I will update the list as and when I learn more about this useful tool.

Which integrated development environment to use for developing node.js applications

I am bias towards Eclipse, and this is partly the reason why I had found Enide Studio. Enide Studio is based on Eclipse, and out of the box, it provides some familiar features which can help me develop node.js applications faster and more easily:

  • Construction of boilerplate coding for projects based on various node.js / JavaScript frameworks.
  • Code assistance which help me remember the module calls which I have to use for my new node.js applications.
  • Debugger to paint me clear pictures of whether my application is doing what I have intended it to do.
  • Eclipse marketplace which I can find the connector to connect to my favorite source code repository system.
  • JSHint which help me identify errors before I ship my node.js application.

How to deal with files

File manipulation is almost inevitable in the applications that I had built in the past. As such one aspect to note down is how I can deal with files in my node.js application.

Writing to file

I could write to a file with codes similar to the following:

var fileSystem = require('fs');

fileSystem.writeFile('HelloWorld.txt', 'Hello World!', function (err) {
  if (err) {
    throw err;
  }
  console.log('Message successfully written!');
});

The above code first gets the file system object via require('fs'). After it had gotten the file system object, it calls its writeFile function, passing it the file to write to, the data to write and a callback function to be called when an attempt is made to write to that file.

In this case, the code will look for a HelloWorld.txt in the same directory as the executing script. Regardless of whether HelloWorld.txt exists or not, it will write the string 'Hello World!' to the file. It will then call the callback function. The callback function checks whether an error had occurred when the node.js script tried to write to the file. If an error had occurred, the error is thrown. If not, 'Message successfully written!' will be logged to console.

Reading from file

I could read from file in my node.js application with codes in a similar form as the following:

var fileSystem = require('fs');

fileSystem.readFile('HelloWorld.txt', function(err, data) {
    if (err) {
        throw err;
    }
    console.log(data.toString());
});

As with the write file example, we will need the file system object to aid us in reading from a file. After I had gotten the file system object, I use its readFile function to read the same file that was created in the write file example. I pass two parameters to the readFile function - the file to read from and a callback function to call when an attempt had been made to read the file.

The callback function will have a Error object and a Buffer object that contains data if the read is successful. In the callback function, I check if an error had occurred while reading the file. If there is, the error is thrown. If not, I will have a Buffer object that represents the content of the file, available via data. I then call the toString function of the Buffer object and send it to console, showing the contents of the file as a string.

How to run a node.js application

The life of a node.js application starts from the first script which is fed to the node executable that comes with my node.js installation. Suppose I had included the node executable in my PATH variable and had the following JavaScript code saved at C:\techcoil\HelloWorld\app.js:

console.log('Hello World');

Running the following command in my shell:

node C:\techcoil\HelloWorld\app.js

results in a node.js application that prints the text Hello World to standard output.

Harnessing the power of others - how to install / uninstall node.js modules with npm

Although node.js provides me with lots of features for me to build my applications, there are still areas which it did not cover for me. Fortunately, there are many brilliant minds out there who had created extension modules for me to build my node.js application on.

Installing a new node.js module to a project codebase

Installing node.js modules is pretty straightforward. I will fire up my command line shell and navigate to my project folder. I will then use the node package manager to install the modules into my project folder.

For example, suppose I want to use the request module in my project to connect to a HTTP server endpoint, I will type the following commands into my windows command prompt:

cd C:\techcoil\helloworld
npm install request

After seeing the following output:

C:\techcoil\helloworld>npm install request
npm http GET https://registry.npmjs.org/request
npm http 200 https://registry.npmjs.org/request
npm http GET https://registry.npmjs.org/request/-/request-2.34.0.tgz
npm http 200 https://registry.npmjs.org/request/-/request-2.34.0.tgz
npm http GET https://registry.npmjs.org/qs
npm http GET https://registry.npmjs.org/json-stringify-safe
npm http GET https://registry.npmjs.org/form-data
npm http GET https://registry.npmjs.org/http-signature
npm http GET https://registry.npmjs.org/aws-sign2
npm http GET https://registry.npmjs.org/oauth-sign
npm http GET https://registry.npmjs.org/forever-agent
npm http GET https://registry.npmjs.org/tunnel-agent
npm http GET https://registry.npmjs.org/hawk
npm http GET https://registry.npmjs.org/tough-cookie
npm http GET https://registry.npmjs.org/node-uuid
npm http GET https://registry.npmjs.org/mime
npm http 200 https://registry.npmjs.org/aws-sign2
npm http GET https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz
npm http 200 https://registry.npmjs.org/json-stringify-safe
npm http GET https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.0.tgz
npm http 200 https://registry.npmjs.org/http-signature
npm http 200 https://registry.npmjs.org/oauth-sign
npm http GET https://registry.npmjs.org/http-signature/-/http-signature-0.10.0.tgz
npm http GET https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz
npm http 200 https://registry.npmjs.org/qs
npm http 200 https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz
npm http GET https://registry.npmjs.org/qs/-/qs-0.6.6.tgz
npm http 200 https://registry.npmjs.org/forever-agent
npm http GET https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz
npm http 200 https://registry.npmjs.org/form-data
npm http GET https://registry.npmjs.org/form-data/-/form-data-0.1.2.tgz
npm http 200 https://registry.npmjs.org/tunnel-agent
npm http GET https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.3.0.tgz
npm http 200 https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.0.tgz
npm http 200 https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz
npm http 200 https://registry.npmjs.org/mime
npm http 200 https://registry.npmjs.org/http-signature/-/http-signature-0.10.0.tgz
npm http 200 https://registry.npmjs.org/qs/-/qs-0.6.6.tgz
npm http 200 https://registry.npmjs.org/form-data/-/form-data-0.1.2.tgz
npm http 200 https://registry.npmjs.org/hawk
npm http 200 https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz
npm http 200 https://registry.npmjs.org/node-uuid
npm http GET https://registry.npmjs.org/hawk/-/hawk-1.0.0.tgz
npm http GET https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.1.tgz
npm http 200 https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.3.0.tgz
npm http 200 https://registry.npmjs.org/tough-cookie
npm http GET https://registry.npmjs.org/tough-cookie/-/tough-cookie-0.12.1.tgz
npm http 200 https://registry.npmjs.org/hawk/-/hawk-1.0.0.tgz
npm http 200 https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.1.tgz
npm http 200 https://registry.npmjs.org/tough-cookie/-/tough-cookie-0.12.1.tgz
npm http GET https://registry.npmjs.org/combined-stream
npm http GET https://registry.npmjs.org/async
npm http GET https://registry.npmjs.org/assert-plus/0.1.2
npm http GET https://registry.npmjs.org/asn1/0.1.11
npm http GET https://registry.npmjs.org/ctype/0.5.2
npm http GET https://registry.npmjs.org/punycode
npm http GET https://registry.npmjs.org/hoek
npm http GET https://registry.npmjs.org/boom
npm http GET https://registry.npmjs.org/cryptiles
npm http GET https://registry.npmjs.org/sntp
npm http 200 https://registry.npmjs.org/combined-stream
npm http GET https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.4.tgz
npm http 200 https://registry.npmjs.org/assert-plus/0.1.2
npm http 200 https://registry.npmjs.org/asn1/0.1.11
npm http 200 https://registry.npmjs.org/ctype/0.5.2
npm http GET https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.2.tgz
npm http GET https://registry.npmjs.org/ctype/-/ctype-0.5.2.tgz
npm http GET https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz
npm http 200 https://registry.npmjs.org/punycode
npm http GET https://registry.npmjs.org/punycode/-/punycode-1.2.4.tgz
npm http 200 https://registry.npmjs.org/async
npm http 200 https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.4.tgz
npm http 200 https://registry.npmjs.org/sntp
npm http GET https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz
npm http 200 https://registry.npmjs.org/boom
npm http GET https://registry.npmjs.org/boom/-/boom-0.4.2.tgz
npm http 200 https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.2.tgz
npm http 200 https://registry.npmjs.org/cryptiles
npm http 200 https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz
npm http GET https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz
npm http 200 https://registry.npmjs.org/punycode/-/punycode-1.2.4.tgz
npm http 200 https://registry.npmjs.org/boom/-/boom-0.4.2.tgz
npm http 200 https://registry.npmjs.org/ctype/-/ctype-0.5.2.tgz
npm http 200 https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz
npm http GET https://registry.npmjs.org/delayed-stream/0.0.5
npm http 200 https://registry.npmjs.org/hoek
npm http 200 https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz
npm http GET https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz
npm http 200 https://registry.npmjs.org/delayed-stream/0.0.5
npm http GET https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz
npm http 200 https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz
npm http 200 https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz
request@2.34.0 node_modules\request
├── json-stringify-safe@5.0.0
├── forever-agent@0.5.2
├── aws-sign2@0.5.0
├── tunnel-agent@0.3.0
├── qs@0.6.6
├── oauth-sign@0.3.0
├── mime@1.2.11
├── node-uuid@1.4.1
├── tough-cookie@0.12.1 (punycode@1.2.4)
├── hawk@1.0.0 (cryptiles@0.2.2, sntp@0.2.4, boom@0.4.2, hoek@0.9.1)
├── form-data@0.1.2 (async@0.2.10, combined-stream@0.0.4)
└── http-signature@0.10.0 (assert-plus@0.1.2, asn1@0.1.11, ctype@0.5.2)

I will then see a directory named as node_modules in C:\techcoil\helloworld. And inside the node_modules folder, there will be a directory named as request that contains the stuff that forms request module.

My application will then be able to use the facilities provided by the request module.

Uninstalling a node.js module

I do this pretty often while experimenting different node.js modules. To uninstall a node.js module from my project codebase, I will navigate to my project and type the command npm uninstall . For example, to remove the request module from my Hello World node.js application, I will type the following commands into my shell:

cd C:\techcoil\helloworld
npm uninstall request

The node package manager will then remove the contents of the request module from my project folder.

Which web framework and HTTP middleware to build my node.js application on

The vanilla node.js installation that I had gotten only provides me with the http module for the creation of a HTTP server. I can have a web server with the following codes:

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end("Hello there!");
}).listen(80);

With this, I make my node.js application listens for HTTP requests on port 80. In this instance, it always reply the text Hello there! as the HTTP response body back to the HTTP client which is rather boring for a web application.

How about serving static resources like images, CSS scripts and JavaScripts? All these features will need a lot of coding effort if I try to build them myself.

Something tells me that Enide Studio had something for me. Indeed, I got an answer when I attempt to create a new project in Enide Studio. I was given a few options in the wizard interface:

  • Node CoffeScript File
  • Node Express Project
  • Node Project
  • Node Source File

After some research on the web, I settled on the Node Express project. The Node Express Project option is awesome: it brings me folders and codes with a good organization structure to get me started in creating HTTP based applications - MVC style. And because express.js is built on top of connect.js, I got a few good features like the ability to serve static files - with just a line of configuration code.

For every node express project, my Enide Studio creates the following in my project root:

  • A folder named as node_modules where node.js modules will be installed by npm. Since I had indicated to create a new Node Express Project, my Enide Studio had ran npm to install express.js and jade into my project folder.
  • A folder named as public for containing static resources of my web based node.js application. I will put all my images, css files, sitemaps, robots.txt and JavaScript files to have them automagically served to my HTTP clients. Awesome!
  • A folder named as routes where I could place controller logic for building HTTP responses back to any HTTP client that connects to my application. Codes in this directory will typically follow a similar structure as the following code snippet:
    exports.index = function(req, res){
      res.render('index', { title: 'Express' });
    };
    

    which in this case renders a HTTP response by looking up a jade template named as index and passing it the text "Express" in via the title attribute.

  • A folder named as views which will contain files that has the extension .jade. These files can then be used by the Jade template engine to render HTML documents for the HTTP clients.
  • A file named as app.js that should be the starting point where we run our node.js application. My Enide Studio gave me one with the following content:
    /**
     * Module dependencies.
     */
    
    var express = require('express')
      , routes = require('./routes')
      , user = require('./routes/user')
      , http = require('http')
      , path = require('path');
    
    var app = express();
    
    app.configure(function(){
      app.set('port', process.env.PORT || 3000);
      app.set('views', __dirname + '/views');
      app.set('view engine', 'jade');
      app.use(express.favicon());
      app.use(express.logger('dev'));
      app.use(express.bodyParser());
      app.use(express.methodOverride());
      app.use(app.router);
      app.use(express.static(path.join(__dirname, 'public')));
    });
    
    app.configure('development', function(){
      app.use(express.errorHandler());
    });
    
    app.get('/', routes.index);
    app.get('/users', user.list);
    
    http.createServer(app).listen(app.get('port'), function(){
      console.log("Express server listening on port " + app.get('port'));
    });
    

    This app.js that my Enide Studio had created for me instantiates a function from the express module. It then calls some functions to configure some basic features for my web applications. It also links some controller logic to handle HTTP requests made to the / and /users urls of my web application. Finally, it creates a HTTP server which will serve HTTP requests based on the configurations set in the earlier line of codes.

  • A file named as package.json which I can use for telling the node package manager what my node.js application depends on. When I enter npm install after I navigates into my project folder, the node package manager will look at this file to bring the dependent modules into the node_modules folder.
  • A file named as README.md that shows me some version information of my Enide Studio.

How to perform logging to file

Logging is certainly not a additional software requirement - it is necessary to ensure that we are able to grow an maintain our software system. Some searches brought me to winston, which I find pretty intuitive to deploy in my node.js application.

To use winston in my node.js application, I would navigate to my project folder with my shell program and enter npm install winston. I can then be able to run codes similar to the following to log messages to a file:


var winston = require('winston');
winston.add(winston.transports.File, { filename: './logs/application.log' });

winston.info('We just got winston running.');
winston.warn('This is a warning message');
winston.error('An error had occurred.');

I first get a logger from the winston library and named it as winston. I then indicate that I want the logger to write to a file named application.log in the logs folder in the same directory as the running process.

I then call the info, warn and error functions to log messages of different log levels.

After running the above codes, I can see a application.log file with the following contents:

{"level":"info","message":"We just got winston running.","timestamp":"2014-06-15T03:06:08.267Z"}
{"level":"warn","message":"This is a warning message","timestamp":"2014-06-15T03:06:08.269Z"}
{"level":"error","message":"An error had occurred.","timestamp":"2014-06-15T03:06:08.270Z"}

How to connect to another web server endpoint

There can be many cases where I want my node.js application to connect to another web server endpoint. For instance, I may have to send billing instructions to the MasterCard Internet Gateway Service to charge my customer for buying my service. Or perhaps I may have to connect to my Apache Solr instance to look through the indexes for my web application's content.

For fulfilling such requirements, I found the request module. By entering npm install request after my shell had navigated to my project folder, I will gain the ability to run the following code:

var request = require('request');
request("http://www.techcoil.com/robots.txt", function(error, response, body) {
  console.log(body);
});

which in this case, utilizes the request module to perform a HTTP get for Techcoil's robots.txt and sends its content to standard output.

How to persist data into my favourite databases

Most applications which I had built so far requires the persistence of data into databases. As such, I am expecting my node.js application to be able to do that as well. Here are some modules which I will use for persisting data to some of my favourite databases.

How to interact with MySQL from my node.js application

I had been with MySQL for quite some time; I had used it in several projects, including Techcoil.com. Naturally, I will want the ability to connect to MySQL from my node.js application for cases where MySQL is a more preferable data persistence option. I guess people who contributed to node.js shared the same thoughts.

I navigated to my project folder and issue "npm install mysql" with my shell and I got the functionality to interact with one of the world's most popular open sourced relational database.

In order to jot some points for manipulating data in my MySQL databases from my node.js applications, a sample scenario will be helpful. Suppose I had a MySQL database instance techcoil and I had granted CRUD access rights to a user account with the following credentials:

  • Username: mary
  • Password: password

And in the techcoil instance, I am going to have a table which is named as Customer that have two columns:

  • firstName
  • lastName

How do I connect to a MySQL database instance from my node.js application

To connect to the MySQL database instance described earlier from my node.js application, I would write the following code:

var mysql = require('mysql');
var mysqlClient = mysql.createClient({
    host: 'localhost',
    user: 'mary',
    password: 'password',
    database: 'techcoil'
});

I call the createClient function provided by the mysql module, passing it an associative array that describe my connection properties. The host attribute indicates the hostname or ip address where my MySQL database server is running from. The user and password attributes define the login credentials for a MySQL user account. And finally, the database attribute indicates the MySQL database instance which we wants to connect to. With that, I get the ability to interact with my MySQL database instance via mysqlClient.

How do I create a table in MySQL database instance from my node.js application

To create the table described earlier, I will run the following code:

mysqlClient.query('CREATE TABLE Customer (firstName VARCHAR(255), lastName VARCHAR(255))', 
	function(err) {
		if (err) {
			console.log(err);
		} else {
			console.log('Creation of table successful');
		}
	}
);

I call the query function provided by the mysql module, passing it an SQL create statement that describes the table schema. I also give the query function a callback to tell me the result of the table creation. If there is an error, I log the error to console, else I log 'Creation of table successful' to the console.

How do I insert records to a table in MySQL database instance from my node.js application

To insert new records to the Customer table, I run the following code:


var saveCustomerCallback = function(err) {
    if (err) {
	console.log(err);
    } else {
	console.log('Insertion successful');
    }
};

var sqlStatementWithPlaceholders = 'INSERT INTO Customer(firstName, lastName) VALUES(?, ?)';

mysqlClient.query( sqlStatementWithPlaceholders, 
	['Mary', 'Jane'],
	saveCustomerCallback
);

mysqlClient.query( sqlStatementWithPlaceholders, 
	['Peter', 'Parker'],
	saveCustomerCallback
);

In order to avoid SQL injection, I first defined a SQL statement with placeholders to contain the first name and last name of my new records. I then call the query function twice to insert Mary Jane and Peter Parker into the Customer database. The first name and last name of a record is contained in an array and will replace the placeholders according to their position in the array. For instance, the first element of the array replaces the first placeholder while the second element of the array replaces the second placeholder.

I also supplied a callback function to inspect the result of the insertion operation. If there is an error, I log the error to console. If not, I log 'Insertion successful' to the console.

How do I select records from a table in MySQL database instance from my node.js application

To select records from the Customer table, I will run the following code:

mysqlClient.query(
		'SELECT * FROM Customer',
		function (err, results, fields) {
			if (err) {
				console.log(err);
			} else {
				console.log(results);
				console.log(fields);
			}
		}
);

I call the query function, passing it an SQL Select statement and a callback. The callback expects 3 parameters:

  1. An error object which will indicate whether the select statement had been successful.
  2. An object which will contain the results of the Select statement if no error had occurred.
  3. An object which will tell me more about the fields that are selected with the Select statement.

Inside the callback function, I log the error to console if there is one. If the Select statement ran smoothly, I log the results and fields selected to the console.

How do I update records in a table in MySQL database instance from my node.js application

Suppose I want to change the first name of Mary Jane to Cindy. To do so, I run the following code.

var sqlStatementWithPlaceholders = 'UPDATE Customer SET firstName = ? WHERE firstName = ? AND lastName = ?';
mysqlClient.query(sqlStatementWithPlaceholders,
		['Cindy', 'Mary', 'Jane'],
		function (err) {
			if (err) {
				console.log(err);
			} else {
				console.log('Update successful.');
			}
		}
);

To avoid SQL injection, I first defined an SQL Update statement with placeholders to contain the data necessary for the update. I then call the query function, sending it the SQL statement, an array of values to replace the placeholders, and a callback function to inspect the outcome of the update. In the callback function, if there is an error, I log it to console, else I log 'Update successful.' to console.

How do I delete records from a table in MySQL database instance from my node.js application

Suppose Peter decided to terminate the service contract with my company. To delete Peter Parker from my Customer table, I will run the following code:

var sqlStatementWithPlaceholders = 'DELETE FROM Customer WHERE firstName = ? AND lastName = ?';
mysqlClient.query(sqlStatementWithPlaceholders, 
		['Peter', 'Parker'], 
		function(err) {
			if (err) {
				console.log(err);
			} else {
				console.log('Delete success.');
			}
		}
);

In order to avoid SQL injection, I first define an SQL DELETE statement with placeholders to contain the data necessary for the delete. I then call the query function, sending it the SQL statement, an array of values to replace the placeholders and a callback function to inspect the outcome of the delete. In the callback function, if there is an error, I log it to console, else I log 'Delete success.' to console.

How to interact with MongoDB from my node.js application

There are a few reasons why I will want to use MongoDB as my database for my next project. For my node.js application to interact with my MongoDB database, I had found the mongoose plugin. To enable my node.js application, helloworld, to be able to use Mongoose, I will type the following commands in my shell application:

cd C:\techcoil\helloworld
npm install request

How to connect to a MongoDB instance from my node.js application via Mongoose

Suppose I have a MongoDB server running at port 31234 on the same machine as my node.js application, I will run the following code to instruct Mongoose to connect to that MongoDB server:

 
var mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:31234/proof-of-concepts', function(err) {
	if (err) {
		console.log(err);
	} else {
		console.log('Connected successfully to localhost MongoDB.');
	}
});

I first get an mongoose object from the mongoose library. After I had gotten the mongoose object, I call its connect function to indicate that subsequent calls to the mongoose framework in the application life cycle connect to the MongoDB server running on port 31234 of the local machine. I also specified the database instance, proof-of-concepts, on which CRUD operations will be performed in.

In addition to the uri, I also supplied a callback to check whether the connection had been successful. If an error had occurred, I log the error to console, else, I log 'Connected successfully to localhost MongoDB.' to console.

How to get started with performing CRUD operations in Mongoose

Mongoose introduces the concept of Schemas and Models. A Schema is a definition of the type of data which documents inside a collection will contain. A Model is an instance of a Schema and is used for interacting with a MongoDB database.

We begin every CRUD operation by defining a Schema and creating a Model from the defined Schema. Suppose I have a collection of Customers, which contains documents with the following fields:

  • Name
  • Date of birth
  • Date of joining

Then I will define the Schema in my node.js application with the following codes:

var customerSchema = new mongoose.Schema({
	name: String,
	dateOfBirth: Date, 
	dateOfJoining: { type: Date, 'default': Date.now }
});

With the Customer Schema defined, I then call the following code to create a Model for me to perform subsequent CRUD operations.

var Customer = mongoose.model('Customer', customerSchema);

With that, Customer will model the customer schema to a MongoDB collection named as 'Customer'. We are then ready to perform CRUD operations on the Customer collection in our MongoDB database instance named as proof-of-concepts.

How to create a new document in MongoDB with mongoose

To create new documents in the Customer collection, I will run the following codes:

var saveCustomerCallback = function (err) {
	if (err) {
		console.log(err);
	} else {
		console.log('Customer record created!');
	}
}

var customer = new Customer({name: 'Cindy', dateOfBirth: new Date('January 1, 1991 07:07:07')});
customer.save(saveCustomerCallback);
 
customer = new Customer({name: 'Jonathan', dateOfBirth: new Date('May 1, 1980 08:08:08')});
customer.save(saveCustomerCallback);
 
customer = new Customer({name: 'James', dateOfBirth: new Date('March 5, 1991 09:07:09')});
customer.save(saveCustomerCallback);

I send my customers' names and birthdays as associative arrays to the Customer function that I had modeled earlier to create new objects. As I had specified in my customer schema that the dateOfJoining field be defaulted to the current date, I do not have to indicate a value for it when I create objects with the Customer function.

I then call the save function that came along with the Customer function to create documents with my customers' data in the Customer collection in my MongoDB server. When I call the save function, I passed in a callback function to know if the document creations were successful.

In the callback, I log the error to console if there is one, else I log 'Customer record created!' to console when the document is created successfully.

How to find documents in MongoDB with mongoose

To look up my customers after I had added them, I run a code similar to the following:


var fillMatchingDocsQueryCallback = function(err, customers) {
	if (err) {
		console.log(err);
	} else {
		console.log(customers);
	}
}

Customer
.where('dateOfBirth').gte(new Date('December 31, 1987 23:59:59'))
.select('name dateOfBirth')
.sort('-name')
.limit(10)
.slaveOk()
.exec(fillMatchingDocsQueryCallback);

In this particular case, I am trying to look for customers who are born after the year 1987.

I first define a callback which accepts two parameters - err and customers for Mongoose to notify me about the document search that I am going to perform later. If an error occurs during the document search, I log it to console. If there are no errors, customers will contain the array of documents that match my search criteria and I log it to console.

I then use the Customer function and chained a few calls which returned a Query object:

  • where('dateOfBirth').gte(new Date('December 31, 1987 23:59:59')) matches documents with the dataOfBirth attribute set to a date greater than December 31, 1987 23:59:59.
  • select('name dateOfBirth') determines that only the name and dateOfBirth attributes of documents be returned from the search.
  • sort('-name') sorts the result with the name in descending order.
  • limit(10) limits the result to contain at most 10 documents.
  • slaveOk() indicates that the search can be performed on MongoDB slave servers.
  • exec(fillMatchingDocsQueryCallback) starts the search and calls fillMatchingDocsQueryCallback when the search outcome is determined.

How to update documents in MongoDB with mongoose

Updating documents is intuitive via instances of Mongoose Models. If I have the Model instance, I just set the attribute to the new value and run the save function on that instance. If not, I can use one of the findXXX method to look up the Model instances.

For example, if I want to change the dateOfJoining attribute for Cindy's document, I can run the following codes:

Customer.findOne({name: 'Cindy'}, function(err, cindy) {
	
	if (err) {
		console.log('Error finding Cindy');
	} else {
		
		cindy.dateOfJoining = new Date('December 31, 2009 10:30:00');
		cindy.save(function(err){
			if (err) {
				console.log(err);
			} else {
                                console.log('Error updating Cindy\'s particulars');
                        }
                   
		});
	}
	
});

In this case, I call the findOne function and pass it an associative array which has a name attribute set to 'Cindy'. I then pass in a callback that expects two parameters. If an error had occurred, I log the error to console. If there are no errors from the search, I set the dateOfJoining field of Cindy's model instance to a new date.

When I am ready to persist the change to my MongoDB server, I call the save function on that instance, passing it a callback to inspect the update outcome. If there is an error, I log the error to console, else I log 'Error updating Cindy's particulars' to console.

How to delete documents in MongoDB with mongoose

Suppose Cindy had decided that she do not want to be my Customer anymore and had requested me to remove her records in my MongoDB database. To do so, I run the following code:

Customer.remove({name: 'Cindy'}, function(err) {
	if (err) {
		console.log(err);
	} else {
		console.log('Document removed successfully');
	}
});

I call the remove function of Customer model, passing it an associative array that includes an attribute with the value 'Cindy' for MongoDB to find Cindy's document for me. I also pass in a callback to inspect the document removal outcome. If an error had occurred during the document removal, I log it to console. Else, I log 'Document removed successfully' to console.

About Clivant

Clivant a.k.a Chai Heng enjoys composing software and building systems to serve people. He owns techcoil.com and hopes that whatever he had written and built so far had benefited people. All views expressed belongs to him and are not representative of the company that he works/worked for.