An Introduction to MongoDB

MongoDB is an open-source, document-oriented, NoSQL database program. If you’ve been involved with the traditional, relational databases for long, the idea of a document-oriented, NoSQL database might indeed sound peculiar. “How can a database not have tables?”, you might wonder. This tutorial introduces you to some of the basic concepts of MongoDB and should help you get started even if you have very limited experience with a database management system.

What’s MongoDB?

Here’s what the official documentation has to say about MongoDB.

MongoDB is an open-source database developed by MongoDB Inc. that’s scalable and flexible. MongoDB stores data in JSON-like documents that can vary in structure.

Obviously, MongoDB is a database system. But why do we need another database option when the existing solutions are inexpensive and successful? A relational database system like MySQL or Oracle has tables, and each table has a number of rows and columns. MongoDB, being a document-oriented database system, doesn’t have them. Instead, it has a JSON-like document structure that is flexible and easy to work with. Here’s an example of what a MongoDB document looks like:

{
   "_id": ObjectId(3da252d3902a),
   "type": "Article",
   "title": "MongoDB Tutorial Part One",
   "description": "First document",
   "author": "Manjunath",
   "content": "This is an..."
}
{
   "_id": ObjectId(8da21ea3902a),
   "type": "Article",
   "title": "MongoDB Tutorial Part Two",
   "description": "Second document",
   "author": "Manjunath",
   "content": "In the second..."
}

A document in a NoSQL database corresponds to a row in an SQL database. A group of documents together is known as a collection, which is roughly synonymous with a table in a relational database. For an in-depth overview of both NoSQL and SQL databases and their differences, we have that covered in the SQL vs NoSQL tutorial.

Apart from being a NoSQL database, MongoDB has a few qualities of its own. I’ve listed some of its key features below:

  • it’s easy to install and set up
  • it uses a BSON (a JSON-like format) to store data
  • it’s easy to map the document objects to your application code
  • it claims to be highly scalable and available, and includes support for out-of-the-box replication
  • it supports MapReduce operations for condensing a large volume of data into useful aggregated results
  • it’s free and open source.

MongoDB appears to overcome the limitations of the age-old relational databases and NoSQL databases. If you aren’t yet convinced about why it’s useful, check out our article on Choosing Between NoSQL and SQL.

Let’s go ahead and install MongoDB.

Installing MongoDB

Installing MongoDB is easy and it doesn’t require much configuration or setup. MongoDB is supported by all major platforms and distributions, and you can check out their documentation if you’re in doubt.

I’ve covered the instructions for installing MongoDB on macOS below.
For Linux, MongoDB recommends installing the software with the help of your distribution’s package manager. If you’re on Windows, it’s as easy as downloading the latest release from from the MongoDB website and running the interactive installer.

Installing MongoDB on macOS using Homebrew

Homebrew is a package manager for macOS, and this tutorial assumes you’ve already installed Homebrew on your machine.

  1. Open the terminal application and run
$ brew update
  1. Once brew is updated, install the mongodb package as follows
$ brew install mongodb
  1. Create a data directory so that the mongod process will be able to write data. By default, the directory is /data/db:

    ```bash
    $ mkdir -p /data/db
    ```
    
  2. Make sure your user account has permission to read and write data into that directory:

    ```bash
    $ sudo chown -R `id -un` /data/db
    > # Enter your password
    ```
    
  3. Initiate the mongo server. Run the mongod command to start the server.

  4. Start the Mongo shell. Open up another terminal window and run mongo. The mongo shell will attempt to connect to the mongo daemon that we initiated earlier. Once you’re successfully connected, you can use the shell as a playground to safely run all your commands.

  5. Exit the Mongo shell by running quit() and the mongo daemon by pressing control + C.

Now that we have the mongo daemon up and running, let’s get acquainted with the MongoDB basics.

Basic Database Operations

Enter the Mongo shell if you haven’t already:

[mj@localhost ~]$ mongo
MongoDB shell version v3.6.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.1

connecting to: test

You can see my version of MongoDB shell when you log in. By default, you’re connected to a test database. You can verify the name of the current database by running db:

> db
test

That’s awesome, but what if we want a new database? To create a database, MongoDB has a use DATABASE_NAME command:

>use exampledb
switched to db exampledb

To display all the existing databases, try show dbs:

> show dbs

local       0.078GB
prototype   0.078GB
test        0.078GB

The exampledb isn’t in the list because we need to insert at least one document into the database. To insert a document, you can do db.COLLECTION_NAME.insertOne({"key":"value"}). Here’s an example:

> db.users.insertOne({'name':'Bob'})
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5a52c53b223039ee9c2daaec")
}

MongoDB automatically creates a new users collection and inserts a document with the key-value pair 'name':'Bob'. The ObjectId returned is the id of document inserted. MongoDB creates a unique ObjectId for each document on creation and it becomes the default value of the _id field:

>show dbs
exampledb   0.078GB
local       0.078GB
prototype   0.078GB
test        0.078GB

Similarly, you can confirm that the collection was created using the show collections command:

> show collections
users

We’ve created a database, added a collection named users and inserted a document into it. Now let’s try dropping it. To drop an existing database, use the dropDatabase() command as exemplified below:

>db.dropDatabase()
{  "ok" : 1 }

show dbs confirms that the database was indeed dropped.

> show dbs
local       0.078GB
prototype   0.078GB
test        0.078GB

For more database operations, see MongoDB reference page on Database Commands.

MongoDB CRUD Operations

As you might already know, the CRUD acronym stands for Create, Read, Update, and Delete. These are the four basic database operations that you can’t avoid while building an application. For instance, any modern application will have the ability to create a new user, read the user data, update the user information and, if needed, delete the user account. Let’s accomplish this at the database level using MongoDB.

Create Operation

Creation is the same as inserting a document into a collection. In the previous section, we had inserted a single document using the db.collection.insertOne() syntax. There’s another method called db.collection.insertMany() that lets you insert multiple documents at once. Here’s the syntax:

> db.COLLECTION_NAME.insertMany(
   [ <document 1> , <document 2>, ... ]
   )

Let’s create a users collection and populate it with some actual users:

> db.users.insertMany([
   { "name": "Tom","age":33, "email": "tom@example.com" },
   { "name":"Bob", "age":35, "email":"bob@example.com" },
   { "name": "Kate", "age": 27, "email": "kate@example.com" },
   { "name": "Watson", "age":15, "email":"watson@example.com"}
])

{
   "acknowledged" : true,
   "insertedIds" : [
      ObjectId("5a52cb2451dd8b08d5a22cf5"),
      ObjectId("5a52cb2451dd8b08d5a22cf6"),
      ObjectId("5a52cb2451dd8b08d5a22cf7"),
      ObjectId("5a52cb2451dd8b08d5a22cf8")
   ]
}

The insertMany method accepts an array of objects and, in return, we get an array of ObjectIds.

Read Operation

Read operation is used to retrieve a document or multiple documents from a collection. The syntax for the read operation is as follows:

> db.collection.find(query, projection)

To retrieve all user documents, you can do this:

> db.users.find().pretty()
{
   "_id" : ObjectId("5a52cb2451dd8b08d5a22cf5"),
   "name" : "Tom",
   "age" : 33,
   "email" : "tom@example.com"
}
{
   "_id" : ObjectId("5a52cb2451dd8b08d5a22cf6"),
   "name" : "Bob",
   "age" : 35,
   "email" : "bob@example.com"
}
{
   "_id" : ObjectId("5a52cb2451dd8b08d5a22cf7"),
   "name" : "Kate",
   "age" : 27,
   "email" : "kate@example.com"
}
{
   "_id" : ObjectId("5a52cb2451dd8b08d5a22cf8"),
   "name" : "Watson",
   "age" : 15,
   "email" : "watson@example.com"
}

This corresponds to the SELECT * FROM USERS query from an SQL database.

The pretty method is a cursor method, and there are many others too. You can chain these methods to modify your query and the documents that are returned by the query.

What if you need to filter queries and return a subset of the collection? Say, find all users who are below 30. You can modify the query like this:

> db.users.find({ "age": { $lt: 30 } })
{ "_id" : ObjectId("5a52cb2451dd8b08d5a22cf7"), "name" : "Kate", "age" : 27, "email" : "kate@example.com" }
{ "_id" : ObjectId("5a52cb2451dd8b08d5a22cf8"), "name" : "Watson", "age" : 15, "email" : "watson@example.com" }

$lt is a query filter operator that selects documents whose age field value is less than 30. There are many comparison and logical query filters available, and you see the entire list in the Query Selector documentation.

Update Operation

The update operation modifies the document in a collection. Similar to the create operation, MongoDB offers two methods for updating a document. They are:

  1. db.collection.updateMany(filter, update, options)
  2. db.collection.updateMany(filter, update, options).

If you need to add an extra field, say registration, to all the existing documents in a collection, you can do something like this:

> db.users.updateMany({}, {$set: { 'registration': 'incomplete'}})
{ "acknowledged" : true, "matchedCount" : 4, "modifiedCount" : 4 }

The first argument is an empty object because we want to update all documents in the collection. The $set is an update operator that sets the value of a field with the specified value. You can verify that the extra field was added using db.users.find().

To update the value of documents that match certain criteria, updateMany() accepts a filter object as the first argument. For instance, you might want to overwrite the value of registration to complete for all users who are aged 18+. Here is what you can do:

> db.users.updateMany(
  {'age':{ $gt: 18} },
  {$set: { 'registration': 'complete'}
})

{ "acknowledged" : true, "matchedCount" : 3, "modifiedCount" : 3 }

To update the registration details of a single user, you can do this:

> db.users.updateOne(
 {'email': 'watson@example.com' },
 {$set: { 'registration': 'complete'}
})

{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

Delete Operation

Delete operation removes a document from the collection. To delete a document, you can use the db.collection.deleteOne(filter, options) method, and to delete multiple documents, you can use the db.collection.deleteMany(filter, options) method.

To delete documents based on certain criteria, you can use the filter operators that we used for the read and update operation:

db.users.deleteMany( { status: { $in: [ "dormant", "inactive" ] } } )

{ "acknowledged" : true, "deletedCount" : 1 }

This deletes all documents with a status of “dormant” or “inactive”.

That’s it.

An Overview of MongoDB Drivers

For an application to communicate with the mongodb-server, you have to use a client-side library called a driver. The driver sits on top of the database server and lets you interact with the database using the driver API. MongoDB has official and third-party drivers for all popular languages and environments.

In this tutorial, we’re going to look at our options for drivers for Node.js. Some drivers add lots of good features, like like schema support and validation of business logic, and you can choose the one that matches your style. The popular drivers for Node.js include the native MongoDB driver and Mongoose. I’ll briefly discuss their features here.

MongoDB Node.js Driver

This is the official MongoDB driver for Node.js. The driver can interact with the database using either promises or callbacks, and also supports the ES6 async/await functions. The example below demonstrates connecting the driver to the server:

const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');

 // Connection URL
  const url = 'mongodb://localhost:27017/exampledb';
 // Database Name
  const dbName = 'exampledb';

(async function() {

  let client;

  try {
    // Attempts to connect to the server
    client = await MongoClient.connect(url);

    console.log("Successfully connected to the server.");

    const db = client.db(dbName);
  } catch (err) {
   //Log errors to console
    console.log(err.stack);
  }

  if (client) {
    client.close();
  }
})();

The MongoClient.connect returns a promise, and any error is caught by the try … catch block. You’ll be implementing the CRUD actions inside the try … catch block, and the API for that is similar to what we’ve covered in this tutorial. You can read more about it in the official documentation page.

Mongoose Driver

Another popular Node.js driver for MongoDB is Mongoose. Mongoose is built on top of the official MongoDB driver. Back when Mongoose was released, it had tons of features that the native MongoDB driver didn’t have. One prominent feature was the ability to define a schema structure that would get mapped onto the database’s collection. However, the latest versions of MongoDB have adopted some of these features in the form of JSON schema and schema validation.

Apart from schema, other fancy features of Mongoose include Models, Validators and middlewares, the populate method, plugins and so on. You can read more about these in the Mongoose docs. Here’s an example to demonstrate mongoose.connect() for connecting to the database:

var mongoose = require('mongoose');

// Connection URL
  const url = 'mongodb://localhost:27017/exampledb';

mongoose.connect(url);

var db = mongoose.connection;

db.on('error',
console.error.bind(console, 'connection error:'));
db.once('open', function() {
  // we're connected!
});

Conclusion

MongoDB is a popular NoSQL database solution that suits modern development requirements. In this tutorial, we’ve covered the basics of MongoDB, the Mongo shell and some of the popular drivers available. We’ve also explored the common database operations and CRUD actions within the Mongo shell. Now it’s time for you to head out and try what we’ve covered here and more. If you want to learn more, I recommend creating a REST API with MongoDB and Node to acquaint yourself with the common database operations and methods.

Sponsors