A Beginner-Level Introduction to MongoDB with Node.js

Introduction

In this article, we are going to talk about how to use the MongoDB database with Node.js. There are couple of ways to do this, including the a popular approach - using an Object Modeling Library. Mongoose is an example of such a library in Node.js, however, we will be using the official MongoDB driver for Node.js.

In this article, we will be connecting to a MongoDB server, create documents, retrieve them from the database and finally delete some.

This will be done through a few scripts, though you'd typically integrate them with a web server/application rather than having them in standalone scripts.

What is MongoDB?

MongoDB is a cross-platform (runs on multiple operating systems), document-oriented database management system (DBMS). MongoDB is also a NoSQL database, which means it does not use SQL to perform operations on a database.

MongoDB uses documents that are in JSON-like format, known as BSON, which is the binary encoding of JSON.

It's developed as an open-source project by MongoDB Inc. under the Server Side Public License.

Node and MongoDB work very-well together, in part because Mongo uses a JavaScript engine built into the database since JavaScript is good at handling JSON objects.

Compared to other databases, such as MySQL, MongoDB is fast for storing certain types of data and can be automatically scaled. It's very simple to implement and get running.

With Mongo being a NoSQL database, it has its own way of storing data. Here are some of the constructs that make up the database structure:

  1. Database: The container that holds a set of collections.
  2. Collection: A set of documents. This is similar to a table in an SQL database. However, unlike an SQL database, a collection does not have a set structure or pre-configured data types.
  3. Documents: A JSON-like object. This is similar to a row in an SQL database. A JSON object may also contain child objects, an array, etc.
  4. _id: Mandatory unique field in every document. It separates one document from another, so we can identify each document independently. If this value is not provided, MongoDB automatically assigns a random value for the field.

Configuration of the Project

Let's start off with the project and skip the npm prompts:

$ npm init -y

Then, let's install the official MongoDB driver:

$ npm install --save mongodb

In order to actually connect to the databse, you'll need to make sure your MongoDB service is running in the background or your development machine. Run the command mongo on your command prompt to enter the Mongo shell:

Running the command show dbs; will present a list of the current databases:

You can exit the shell by running the exit command.

Unlike SQL databases, which require a database to be created before usage - there's no need to create a database or a collection beforehand. They'll automatically be created when required.

Implementing CRUD Operations

With our project initialized and MongoDB installed, we can get down to writing some CRUD logic.

Connecting to the Database

Of course, to use MongoDB in code, we need to import the module:

const mongodb = require('mongodb');

Then, let's instantiate a client:

const MongoClient = mongodb.MongoClient;

The client needs to know where to connect, so we'll supply it with a url and dbName:

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

// Database Name
const dbName = 'userdb';

Finally, let's try connecting to the database:

// Use the connect method to create a connection w/ the database
MongoClient.connect(url, (err, client) => {
    if (err) {
        throw err;
        return;
    }

    console.log('Database connection successful');

    // This objects holds the refrence to the db
    const db = client.db(dbName);

    client.close();
});

If you have connected to the database sucessfully you should see the output:

Database connection successful

Otherwise you'll be greeted with an error message. Check if the server is up and running and if the username and password are correct in that case.

As you can see in the example, the MongoClient.connect method takes two parameters, the URL of the database and the callback function.

The callback function has two parameters: err and client.

The first parameter would contain an error if there is any network issue or any other issue with connecting to the database. If there are no issues, the error will be null.

The second parameter is the client object, which we use to interact with the database.

The db property of the client holds a reference to the database. To perform any action on that database, we use this reference.

Create a Document

To perform any action on the database, you have to be connected to it, obviously. With Mongo, there are two ways of inserting documents into the database. The first way is to add a single document at a time. We can use the insertOne() method to achieve this:

const collection = db.collection('userdb');

// Insert one document
collection.insertOne({
    firstName: 'john',
    lastName: 'doe',
    age: 21,
    hobbies: [
        'Reading books',
        'Collecting stamps'
    ]
}, (err, result) => {
    if (err) {
        console.log(err);
        return;
    }
    
    console.log(result.result);
});

The result paramater of the callback contains information about the query. It has a field called result which looks like:

result: { n: 1, ok: 1 }
Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

n is the number of documents inserted. ok is the he status of the command.

You don't have to excplicitly create a database named userdb, or a collection named users before inserting the document. The database and the collection will be automatically created.

The second method allows you to add multiple documents at once. We can use the insertMany() method to achieve this:

// Insert multiple documents
collection.insertMany([
    {
        firstName: 'john',
        lastName: 'doe',
        age: 21,
        hobbies: [
            'Reading books',
            'Collecting stamps'
        ]
    }, {
        firstName: 'anna',
        lastName: 'dias',
        age: 20,
        hobbies: []
    }
], (err, result) => {
    if (err) {
        console.log(err);
        return;
    }
    
    console.log(result.ops);
});

Running this piece of code will yield:

[ { _id: 1,
    firstName: 'john',
    lastName: 'doe',
    age: 21,
    hobbies: [ 'Reading books', 'Collecting stamps' ] },
  { _id: 2,
    firstName: 'anna',
    lastName: 'dias',
    age: 20,
    hobbies: [] } ]

Since we have not defined an _id for either of these documents, we can fetch the assigned _id from the result['ops'] object if we ever need access to the generated _id.

In addition to that, you can define the _id yourself:

// Insert one document
collection.insertOne({
    _id: 'someuniqueid',    // Our specified ID
    firstName: 'john',
    lastName: 'doe',
    age: 21,
    hobbies: [
        'Reading books',
        'Collecting stamps'
    ]
}, (err, result) => {
    if (err) {
        console.log(err);
        return;
    }
    
    console.log(result.result);
});

Retrieving Documents

Retrieve all Documents

First, let's look at how to fetch all documents from a collection:

// Find all documents
collection.find({}).toArray((err, docs) => {
    if (err) {
        throw err;
    }
    console.log(docs)
});

Running this piece of code will yield us:

[{ _id: 1,
    firstName: 'john',
    lastName: 'doe',
    age: 21,
    hobbies: [ 'Reading books', 'Collecting stamps' ] },
  { _id: 2,
    firstName: 'anna',
    lastName: 'dias',
    age: 20,
    hobbies: [] } ]

As you can see in the example, we have passed an empty object ({}) as the query.

According to the documentation, the toArray() method returns an array that contains all the documents from a cursor. The method iterates the cursor completely, loading all the documents into RAM and exhausting the cursor.

The documents fetched by the collection will be assigned to the docs parameter in the callback function.

Find Documents with a Query Filter

The next method of finding a document is to use a query filter. For example, the following query selects the users with the first name john:

{
    'firstName': 'john'
}

And to do this in code:

collection.find({
    firstName: 'john'
}).toArray((err, docs) => {
    if (err) {
        throw err;
    }
    console.log(docs)
});

This code will result in:

[{ _id: 1,
    firstName: 'john',
    lastName: 'doe',
    age: 21,
    hobbies: [ 'Reading books', 'Collecting stamps' ] } ]

Evidently, all records with the firstName john are returned.

Updating a Document

The next operation we are going to talk about is updating a document. To update a single document, similar to retrieving a document, we can use the updateOne() method:

collection.updateOne(
    // The query filter
    {
        firstName: 'john'
    },
    // The update values
    {
        $set: {
            lastName: 'well',
            edited: true
        }
    },
    (err, result) => {
        if (err) {
            throw err;
        }
        console.log(result.result);
    }
);

This code results in:

{ n: 1, nModified: 1, ok: 1 }

As you can see in the example, the updateOne() method accepts three parameters. The first one is the query filter. The second one are the update values. The third one is the callback function, which accepts the error and the results as parameters.

Again, the results here notify us of the status (ok), the number of documents selected for the update (n) and the number of updated documents (nModified).

n can be greater than nModified, if a field is updated with the value it already had.

Using this query, we have selected one document where the field firstName is john and we have changed the lastName of that document to well. Also, we have added a field called edited and set it as true. Notice how we have not needed to specify or follow any schema during this whole process. Mongo just accepts any data you send it.

If you are using the updateOne() method, the query will select the first document with the matching field. If there are multiple documents with a field of the same value, using the updateMany() method will update them all, which in some cases might not be what we want to do.

Note: If you are using the updateOne() method, ideally the query should only select a single document. Otherwise, we cannot predict the document that might get udpated. So keep this in mind and be cautious when using a query filter that could match multiple documents.

We can also edit all the documents which satisfy the condition that the field firstName is john:

collection.updateMany(
    // The query filter
    {
        firstName: 'john'
    },
    // The update values
    {
        $set: {
            lastName: 'well',
            edited: true
        }
    },
    (err, result) => {
        if (err) {
            throw err;
        }
        console.log(result.result);
    }
);

The updateMany() method is similar to the updateOne() method, except it updates all the documents that match the query filter.

Removing a Document

We can use the deleteOne() or deleteMany() methods to remove a document from a collection:

collection.deleteOne(
    // The query filter
    {
        firstName: 'john'
    },
    (err, result) => {
        if (err) {
            throw err;
        }
        console.log(result.result);
    }
);

This code results in:

{ n: 1, ok: 1 }

Again, in a similar fashion to the previous examples - the first accepted parameter is the filter query and the second parameters is the callback function. The callback function returns an error or a result.

Running this piece of code will remove a document that matches the query - in this case, a document in which the firstName field is john. Again, this will only delete the first document that matches the query.

You can also use the deleteMany method to delete all the documents which are selected:

collection.deleteMany(
    // The query filter
    {
        firstName: 'john'
    },
    (err, result) => {
        if (err) {
            throw err;
        }
        console.log(result.result);
    }
);

Conclusion

MongoDB is a popular NoSQL, lightweight database that's really easy to implement and use with Node. We wrote a very simple Node application that interacts with a MongoDB to create, retrieve and delete collections.

As always the source code is available on GitHub.

Last Updated: February 5th, 2020
Was this article helpful?

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms