Connecting Node.js application to MongoDB on Ubuntu 16.04

2017-11-14 By Tan 400 Views Node.js Ubuntu MongoDB

Introduction

Node.js is a free, open-source and cross-platform Javascript run-time environment to execute server-side Javascript code. It can be used to develop intensive and dynamic web applications such as video streaming sites and single-page applications.

MongoDB is a document database that is easily scaleable due to it's built-in distributed database design. MongoDB provides high flexibility and availability through horizontal scaling and geographic distribution. In contrast to relational database, MongoDB does not require a deep predefined schema before you can add data since it can be altered at any time. As it uses the NoSQL concept, data rows are stored in JSON-like documents which allows arbitrary data to be inserted.

Great! Let’s now look at how to connect Node.js to MongoDB on Ubuntu 16.04.

Prerequisites

  • Ubuntu 16.04 server with non-root user
  • MongoDB
  • Node.js

This tutorial assumes that you are running an Ubuntu 16.04 server which has a non-root user account with sudo privileges to administer your server. We also assume that MongoDB and Node.js have been installed previously.

Step 1 - Verify MongoDB and Node.js are running

Before we start, let's verify that MongoDB is running on the server:

ps -ef | grep mongo

The sample output below verifies that MongoDB is running:

[secondary_label Output]
mongodb    982     1  1 14:27 ?        00:00:10 /usr/bin/mongod --config /etc/mongod.conf

If it's not running, issue the following command to start the MongoDB daemon:

sudo systemctl start mongod

Since systemctl does not provide output, we need to verify that the service has started properly:

sudo systemctl status mongod

You should see an output similar to the following:

[secondary_label Output]
● mongod.service - High-performance, schema-free document-oriented database
   Loaded: loaded (/lib/systemd/system/mongod.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2017-11-08 14:27:38 MYT; 14min ago
     Docs: https://docs.mongodb.org/manual
 Main PID: 982 (mongod)
    Tasks: 20
   Memory: 64.1M
      CPU: 11.895s
   CGroup: /system.slice/mongod.service
           └─982 /usr/bin/mongod --config /etc/mongod.conf

Nov 08 14:27:38 ubuntuxenial systemd[1]: Started High-performance, schema-free document-oriented database.

There is a console client that comes with MongoDB. To launch it, issue the following command:

mongo

You will see an output like this (you can ignore the warnings):

[secondary_label Output]
MongoDB shell version v3.4.10
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.10
Server has startup warnings:
2017-11-08T14:27:38.497+0800 I STORAGE  [initandlisten]
2017-11-08T14:27:38.497+0800 I STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
2017-11-08T14:27:38.497+0800 I STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem
2017-11-08T14:27:38.827+0800 I CONTROL  [initandlisten]
2017-11-08T14:27:38.828+0800 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2017-11-08T14:27:38.828+0800 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2017-11-08T14:27:38.828+0800 I CONTROL  [initandlisten]
2017-11-08T14:27:38.828+0800 I CONTROL  [initandlisten]
2017-11-08T14:27:38.828+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2017-11-08T14:27:38.828+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-11-08T14:27:38.828+0800 I CONTROL  [initandlisten]
2017-11-08T14:27:38.828+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2017-11-08T14:27:38.828+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-11-08T14:27:38.828+0800 I CONTROL  [initandlisten]
. . .

Run this command to list the existing databases:

show dbs

Run this command to display the selected database:

db

Run the following command to switch to the "test" database and display the collections it contains (if any):

use test
show collections

Here is a list of commands that you can use in the console client, you can get the full list of commands by typing "help":

[secondary_label commands]
show dbs                  # show database names
show collections          # show collections in current database
show users                # show users in current database
show profile              # show most recent system.profile entries with time >= 1ms
show logs                 # show the accessible logger names
show log [name]           # prints out the last segment of log in memory, 'global' is default
use <db_name>             #  set current database
db.foo.find()             # list objects in collection foo
db.foo.find( { a : 1 } )  # list objects in foo where a == 1
it                        # result of the last line evaluated; use to further iterate
exit                      # quit the mongo shell

Next, let's verify that Node.js is running:

node -v

You should see the Node.js version as the command output. The next step we need to do is to install the driver which connects Node.js to MongoDB.

Step 2 - Installing the MongoDB Node.js Driver

This driver is the officially supported Node.js driver for MongoDB. It is written in pure JavaScript and provides a native asynchronous Node.js interface to MongoDB.

Use the node package manager npm to install the driver:

npm install mongodb

If you get an output similar to below, that means your npm package directory has not been initialized yet:

[label Output]
npm WARN enoent ENOENT: no such file or directory, open <^>'/Users/muser/package.json'<^>
npm WARN muser No description
npm WARN muser No repository field.
npm WARN muser No README data
npm WARN muser No license field.

To initialize the npm package directory, use the following command:

npm init

Enter your details in the various prompts. You can also press Enter for default.

Once the MongoDB driver has been installed, we will create a file for connecting to the MongoDB database.

Step 3 - Connecting to MongoDB

Now it is time to write the code that will allow your Node.js application to connect to MongoDB. To be able to execute your code, we will need to create a new file which we will call connect.js.

Once you create the file, use your preferred editor to add the following code:

[label connect.js]
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');

var url = 'mongodb://localhost:27017/test';
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server.");
  db.close();
});

Next, we want to test if Node.js can connect to MongoDB properly. Execute the connect.js file by typing the following command:

node connect.js

You should see the following string in the output

[label Output]
Connected correctly to server.

Great! Now that we have confirmed that Node.js is able to connect to MongoDB successfully, we want to test querying the database. Before we can do that, we need to import a sample database.

Step 4 - Importing a Sample MongoDB Collections

In this step, we will download a sample dataset called restaurants:

wget  https://raw.githubusercontent.com/mongodb/docs-assets/primer-dataset/primer-dataset.json

Once the download is completed, we import it into the MongoDB test database:

mongoimport --db test --collection restaurants --drop --file primer-dataset.json

You should see the following output:

[label Output]
2017-11-08T14:49:20.729+0800    connected to: localhost
2017-11-08T14:49:20.731+0800    dropping: test.restaurants
2017-11-08T14:49:22.073+0800    imported 25359 documents

You can see that in this sample, there are 25359 documents (traditionally called 'records'). The sample which you will download may have different number of documents. Now, that we have imported a sample dataset, let's try to query the database.

Step 5 - Query by Top Level Field in the Sample Collections

Now, create a new file called topquery.js using your preferred editor to add the following code:

[label topquery.js]
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var url = 'mongodb://localhost:27017/test';

var findRestaurants = function(db, callback) {
   var cursor =db.collection('restaurants').find( { <^>"name": "Vella"<^> } );
   cursor.each(function(err, doc) {
      assert.equal(err, null);
      if (doc != null) {
         console.dir(doc);
      } else {
         callback();
      }
   });
};

MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);

  findRestaurants(db, function() {
      db.close();
  });
});

The code above is to run a query on the sample dataset to find a restaurant that has the name "Vella". Execute the command to run the code:

node topquery.js

You should see the following output:

[label Output]
{ _id:
   ObjectID {
     _bsontype: 'ObjectID',
     id: Buffer [ 90, 2, 151, 67, 90, 145, 113, 140, 98, 26, 241, 96 ] },
  address:
   { building: '1480',
     coord: [ -73.9557413, 40.7720266 ],
     street: '2 Avenue',
     zipcode: '10075' },
  borough: 'Manhattan',
  cuisine: 'Italian',
  grades:
   [ { date: 2014-10-01T00:00:00.000Z, grade: 'A', score: 11 },
     { date: 2014-01-16T00:00:00.000Z, grade: 'B', score: 17 } ],
  name: 'Vella',
  restaurant_id: '41704620' }

Next, let's try to run a query on an embedded document. This means that the query will attempt to filter the results based on a sub-level field.

Step 6 - Query by Field in an Embedded Document

Use your preferred editor to add the following code to a new file called embeddedquery.js:

[label embeddedquery.js]
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var url = 'mongodb://localhost:27017/test';

var findRestaurants = function(db, callback) {
   var cursor =db.collection('restaurants').find( { <^>"address.zipcode": "10075"<^> } );
   cursor.each(function(err, doc) {
      assert.equal(err, null);
      if (doc != null) {
         console.dir(doc);
      } else {
         callback();
      }
   });
};

MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);

  findRestaurants(db, function() {
      db.close();
  });
});

The code above runs a query on the sample dataset to find all restaurants that has the zipcode "10075". Execute the command to run the code:

node embeddedquery.js

This time the query will display all the restaurants with the zipcode "10075" which turns out to be quite many. Your output should scroll and end as per below:

[label Output]
. . .
{ _id:
   ObjectID {
     _bsontype: 'ObjectID',
     id: Buffer [ 90, 2, 168, 242, 124, 32, 206, 179, 252, 33, 124, 184 ] },
  address:
   { building: '1146',
     coord: [ -73.9588694, 40.7753242 ],
     street: 'Lexington Ave',
     zipcode: '10075' },
  borough: 'Manhattan',
  cuisine: 'Other',
  grades: [],
  name: 'Vive La Crepe',
  restaurant_id: '50018368' }
{ _id:
   ObjectID {
     _bsontype: 'ObjectID',
     id: Buffer [ 90, 2, 168, 242, 124, 32, 206, 179, 252, 33, 125, 175 ] },
  address:
   { building: '1501',
     coord: [ -73.95326539999999, 40.7719867 ],
     street: '1St Ave',
     zipcode: '10075' },
  borough: 'Manhattan',
  cuisine: 'Other',
  grades: [],
  name: '',
  restaurant_id: '50018889' }

Congratulations! You now have the ability to connect and query data from your MongoDB database using a Node.js application on Ubuntu 16.04!