Many of today’s web applications use node.js in conjunction with MongoDB to store and access data on the backend server. Not only does node.js excel in ease of access to non-relational databases like MongoDB, but brings scalability and speed to the server side of your app.
With the growing popularity of MEAN (MongoDB, Express, Angular and Node) and MERN (MongoDB, Express, React and Node) stacks, proficiency in CRUD operations on NoSQL databases like MongoDB is something every app developer should have. Fortunately, it’s fairly simple and easy, especially with the delicious tutorial we’ve prepared just for you.
How can a tutorial be delicious? Is using Node.js with MongoDB really simpler than ordering dinner? Keep reading to find out!
Before we start cooking, let’s get to know our ingredients.
Node.js is a JavaScript runtime environment for the back-end of your application. Based on Google’s V8 JavaScript engine, Node.js includes numerous components and features necessary for web app implementation.
One of the main advantages of Node.js is its scalability thanks to its event-driven asynchronous engine. Since it continues working on other tasks in the queue instead of waiting for the client to respond, it can perform many more operations in parallel – and thus faster.
In addition, Node.js supports the quick installation of third party packages and modules using the npm tool, which we will also use in this tutorial to install MongoDB.
MongoDB is an open source non-relational database that stores the data in the form of collections and documents. Designed with agility and scalability in mind, MongoDB brings together the rich features of relational databases and speed of key-value stores.
Instead of storing data in rows and columns (as relational databases do), MongoDB stores the JSON documents in the form of collections with dynamic schemas. Storing all related information together makes querying faster, and since MongoDB was also designed to be used asynchronously, it makes for an ideal repository for the data of Node.js applications.
In this tutorial, we’ll be installing MongoDB on your local machine, but for production purposes, you might want to use the MongoDB Atlas cloud database service.
If you have yet to do so, download and install MongoDB on your machine using the file that matches your OS and processor. Once installed, run MongoDB from the command prompt of your operating system. If you use the default settings, the port on which MongoDB will listen will be 27017.
Now that we have our ingredients ready, it’s time to get cooking and introduce them to one another.
1. Installing MongoDB npm
Regardless of whether you have a Node.js project you’re looking to connect to a MongoDB database or you are creating a new project, you’ll need to install the MongoDB package using the Node.js Package Manager (npm). To do that, open a terminal window in your IDE of choice, and type:
npm install -g mongodb
This will install mongodb as a global library, so all your Node.js projects will have access to it and be able to use it.
2. Connecting to MongoDB
With your kitchen (the backend) and ingredients in place, it’s time to mix those flavors. Create a file in your project folder named server.js. As the name implies, this will be your server, and it will be bringing out the dishes (or any other kind of data) you’ll have in your MongoDB database.
To allow Node.js access to MongoDB as a client, you’ll need to enter the requirement in your server.js file.
const {MongoClient} = require('mongodb');
To connect Node.js to the actual MongoDB database server running locally on your machine, we’ll need to specify its URL. If you didn’t make any changes in the setup process, the URL should be:
const url = 'mongodb://localhost:27017/';
With the above lines in our server.js file, we now have access to all the CRUD functions of mongoClient. CRUD stands for Create, Read, Update and Delete – the basic functions you will be applying on your database.
So let’s start with the first: Creation.
In our mouth-watering Dinner project, we’ll be creating a database of dishes we could order. To start, we’ll be adding a document (a dish) into a collection named dishes in a database that we’ll (fairly unoriginally) name
dishesdb
. Now comes the neat part about cooking with MongoDB and Node.js – you don’t have to declare the names of the database and collection in advance. If they do not exist when we call them, they will be created when we insert a document into a collection.
To insert delicious dishes (documents) into our menu (collection), we can use one of two methods. To add a single dish, we’ll use
insertOne()
, and to add a number of dishes at once we’ll be using insertMany()
.The code below, once executed, will attempt to add a single dish, “Greens Fava Salad”, to the collection dishes in the database dishesdb. The variable dbo is used to refer to our database (dishesdb), and in it we’re creating a collection named dishes using the
collection()
method.Since we won’t be using a frontend for the purpose of this tutorial, we’ll be tracking what happens on the server through terminal output. To view the results of script execution, we’ll use
console.log()
and specify a success message to display – 1 document inserted into collection dishes.Here’s a function to insert one single dish into our database,
dishesdb
:async function createOne(dbName, collectionName, newdish) {
const client = await MongoClient.connect(url, {useNewUrlParser: true});
await client.db(dbName).collection(collectionName).insertOne(newdish);
console.log("1 document inserted into collection dishes");
client.close();
}
Now all we need to do is define a new dish and then call the function:
let newdish = {
innerId: 1,
title: 'Greens Fava Salad',
description: 'Tossed greens with citrus dressing.',
price: '$10'
};
await createOne('dishesdb', 'dishes', newdish);
Note that it’s important to close the database connection at the completion of every interaction using
client.close()
. Leaving connections open can be a security vulnerability as well as cause errors and malfunctions. In addition, if you want to simplify your code and improve performance you can use this method to share a single database connection across your entire codebase.
To test it out add the code above to your server.js file and run node server.js in a terminal. If all goes well, you should receive the message – 1 document inserted into collection dishes.
Inserting multiple items into your collection is very similar. You simply need to use
insertMany()
instead of insertOne()
. Here’s a function to insert many dishes into our database,
dishesdb
:async function createMany(dbName, collectionName, mydishes) {
const client = await MongoClient.connect(url, {useNewUrlParser: true});
const res = await client.db(dbName).collection(collectionName).insertMany(mydishes);
console.log("Number of dishes added:", res.insertedCount);
client.close();
}
Now all we need to do is define a few dishes and then call the function:
let mydishes = [
{ innerId: 2, title: 'Seasonal Pumpkin Soup', description: 'Hot and filling Thai Pumpkin Soup.', price: '$13'},
{ innerId: 3, title: 'Fresh Vegetables', description: 'Freshly cut vegetables with olive oil and zest.', price: '$10'},
{ innerId: 4, title: 'New York Cheesecake', description: 'Delicious Cheesecake with an accompaniment of seasonal fruits.', price: '$20'},
{ innerId: 5, title: 'Chocolate Donut', description: 'Our chef\' s recipe for a chocolate donut.', price: '$15'},
{ innerId: 6, title: 'Watermelon Cocktail', description: 'A light alcoholic cocktail to cleanse your pallet.', price: '$17'}
];
await createMany('dishesdb', 'dishes', mydishes);
As you can see, in addition to the title and description of each dish, we also added our own unique identifiers for the dishes / documents (innerId) to prevent confusion between the identification scheme of our Dinner menu and the MongoDB index for documents.
Now that we have some documents in a collection stored in the database, we can read them.
To read from the DB we can use
find()
and findOne()
. To get all the content of a collection, we can use find() without any qualifying queries.Here’s a function using
find()
to locate all of the documents of collection collectionName
in database dbName
.async function locateAll(dbName, collectionName) {
const client = await MongoClient.connect(url, {useNewUrlParser: true});
const result = await client.db(dbName).collection(collectionName).find({}).toArray();
console.log(result);
client.close();
}
Running this function for database dishesdb and collection dishes looks like this:
await locateAll('dishesdb', 'dishes');
The result will be all 6 dishes that are currently listed in collection ‘dishes’.
We can make the search more specific by adding a query to the
find()
function. For example, here is a function that accepts a specific query in addition to the
dbName
and collectionName
. async function locateByQuery(dbName, collectionName, myQuery) {
const client = await MongoClient.connect(url, {useNewUrlParser: true});
const result = await client.db(dbName).collection(collectionName).find(myQuery).toArray();
console.log(result);
client.close();
}
Here is how we define a query to locate all the dishes priced at $10 and then call the function.
let myquery = { price: '$10' }; await locateByQuery('dishesdb', 'dishes', myquery);<br>
let myquery = { price: '$10' };
await locateByQuery('dishesdb', 'dishes', myquery);
If we’re looking to find only one specific document we can use
findOne()
. It works pretty much like find()
except it will always return a single object – the first document to match the query. So if we change the above code to findOne()
instead of find()
, we’ll only get the first item on our menu to cost $10.Here’s the function
locateOneByQuery()
that does exactly that:async function locateOneByQuery(dbName, collectionName, myQuery) {
const client = await MongoClient.connect(url, {useNewUrlParser: true});
const result = await client.db(dbName).collection(collectionName).findOne(myQuery);
console.log(result);
client.close();
}
The next operation in CRUD is Update and as the name implies, it allows us to update documents in our MangoDB database collections.
Much like with creating and reading, updates to documents can be done in singles or in bulk. To update one document we can use
updateOne()
and updateMany()
to change values in a number of documents at once.With
updateMany()
, you can alter the values of multiple documents that match a query. updateOne()
will update the first document to match it in our collection.Here’s a function for updating one document that expects the dbName and collectionName in addition to the query and the new values:
async function renewOneByQuery(dbName, collectionName, myQuery, newValue)
{
const client = await MongoClient.connect(url, {useNewUrlParser: true});
const res = await client.db(dbName).collection(collectionName).updateOne(myQuery, newValue);
console.log("number of documents updated:", res.result.nModified);
client.close();
}
For example, let’s make our soup extra-attractive by updating the name and description. From ‘Seasonal Pumpkin Soup’, we’ll change the name to ‘Autumn Pumpkin Soup’ and include some details about the soup’s unique properties in the description.
The code to do that would look like this:
let newQuery = { title: 'Seasonal Pumpkin Soup' };
let newValue = { $set: {title: 'Autumn Pumpkin Soup', description: 'Hot and filling Bengali Pumpkin Soup.' }};
await renewOneByQuery('dishesdb', 'dishes', newQuery, newValue);
With such appetizing names and descriptions, our dishes seem underpriced, wouldn’t you agree? So let’s raise some prices.
In order to change the price of all dishes costing ‘$10’ to ‘$20’, let’s create a function that updates many documents at once based on our given query. The function code would look like this:
async function renewManyByQuery(dbName, collectionName, myQuery, newValue) {
const client = await MongoClient.connect(url, {useNewUrlParser: true});
const res = await client.db(dbName).collection(collectionName).updateMany(myQuery, newValue);
console.log("number of documents updated:", res.result.nModified);
client.close();
}
The code defining the query and new values would look like this:
let newQuery = { price: '$10' };
let newValue = { $set: {price: '$20' }};
await renewManyByQuery('dishesdb', 'dishes', newQuery, newValue);
This will update the price on dishes 1 and 3 from $10 to $20.
The D in CRUD stands for Deletion, so this is the last function we’ll look at. As with creating, reading and updating, we can delete one document or multiple ones with
deleteOne()
and deleteMany()
.To delete a single item from our menu, in this case the item with the innerId value 1, we’ll first add this function to our server.js file:
async function removeOneByQuery(dbName, collectionName, myQuery) {
const client = await MongoClient.connect(url, {useNewUrlParser: true});
const obj = await client.db(dbName).collection(collectionName).deleteOne(myQuery);
console.log("document deleted:", obj.result.n);
client.close();
}
Then we’ll call the function like this:
let myQuery = { innerId: 1 };
await removeOneByQuery('dishesdb', 'dishes', myQuery);
Just like deleting one document we can delete many. Here’s the function to delete all documents that fit the given query:
async function removeManyByQuery(dbName, collectionName, myQuery) {
const client = await MongoClient.connect(url, {useNewUrlParser: true});
const obj = await client.db(dbName).collection(collectionName).deleteMany(myQuery, newValue);
console.log("document(s) deleted:", obj.result.n);
client.close();
}
In this case we’ll call the function without specifying any query so calling the function will delete ALL documents in the dishes collection:
await removeManyByQuery('dishesdb', 'dishes', {});
With these commands, we’ve covered pretty much all you need to know to use MongoDB with Node.js.
The next step (once you’ve grabbed something quick to eat to satisfy the munchies we just gave you) is adding a frontend and Express.js to interconnect your app with the backend we just created. With those in place, you’ll be able to expand the Dinner we cooked into a web app with visuals and UX to make a user salivate.