Using MongoDB and Mongoose to Develop Full-Stack Apps

Learn the basics of the most popular NoSQL database and how you can use it to quickly build full-stack applications.

Advaith Malka
TechTalkers
10 min readMay 10, 2021

--

MongoDB logo (Credit: Syed Zainul)

Released in 2009, MongoDB quickly rose to popularity among developers due to its ease of use while still being able to perform complex functions. While many other companies offered NoSQL database systems before MongoDB, they proved ineffective and failed to take market share away from their SQL counterparts. Today, MongoDB secures 24.6% of the market share of all database systems and is by far the most popular NoSQL database system. With its ever-increasing popularity, MongoDB is an essential tool to have in your developer toolbox.

MongoDB is quickly catching up with its SQL counterparts.

In this tutorial, we will be going over the basics of storing and retrieving data in a NoSQL database and how you can use Mongoose.js to build applications faster.

Prerequisites: Experience with Node.js and ES8 JavaScript (async, await) is recommended.

What Is a NoSQL Database?

NoSQL databases offer many powerful features (Credit: EDUCBA)

You have probably heard of SQL databases. These databases relationally store data that can be interacted with using a query language called SQL. SQL stores data in multiple tables, which then can be joined together to compare and aggregate large amounts of data. NoSQL, on the other hand, stores data in JSON-like objects called documents. Each document is like a row in a SQL database and consists of key-value pairs, just like JavaScript objects.

What is Mongoose.js?

Mongoose.js is a MongoDB ODM for Node.js. An Object Document Mapper (ODM) is something that maps objects to a document database like MongoDB. Under the hood, it uses the native MongoDB driver for Node.js but provides some additional benefits including the ability to define schemas, enforce a type system, validate data, and use asynchronous JavaScript functions.

Setting up MongoDB Atlas

To host your MongoDB Database on the cloud, you will need a MongoDB Atlas account. Once you have created one, it should prompt you to create an organization. If you are just making an account for yourself, you can put whatever name you want. Under “Select Cloud Service”, make sure MongoDB Atlas is selected (not Cloud Manager).

Create an organization after creating your MongoDB Atlas account. Also, make sure MongoDB Atlas is selected and that you are not using Cloud Manager.

Now that you have created your organization, it’s time to create your first project. Click on the “New Project” button and give it a name.

Create a project by clicking the “New Project” button.

When you see the screen shown below, give your project a name.

Name your project.

Next, we need to build a cluster. A cluster is a server where your MongoDB database is stored. MongoDB offers a wide variety of options when it comes to clusters. From M0 (free) with 512 MB of storage up to M700 (33.28/hr) with 4 TB of capacity.

To create a new cluster, click the green button in the middle of the screen (shown below). For now, you should create a free cluster since we are just testing out MongoDB.

Build a cluster that will store your database.

Now, you should be on the cluster specs screen (shown below). You can choose from three different providers to host your database: Amazon AWS, Google Cloud, and Microsoft Azure. I would recommend you choose the provider closest to your location for the best network performance.

Choose the closest region and click “Create Cluster” to finish building your cluster.

Your cluster should begin building automatically after clicking “Create Cluster.” This operation usually takes 2–5 minutes.

After your cluster has finished building, you will need to create a database. You can do that by clicking on the Collections button, which is located right under the name of your cluster. Then, click the grey, “Add My Own Data” button and enter a name for your database.

Click “Collections” and create a database.

You will also need to provide a name for your first collection. Collections are similar to tables from a SQL database and contain documents with key-value data pairs. For this tutorial, name your collection “users”, as shown below.

Name your database and your first collection. Collection names should describe the data stored in them.

Now, it’s finally time to start coding!

Connecting to Our Database

Now, with all the database config out of the way, it’s finally time to write some code!

If you don’t already have NPM on your computer, install it here. In a new folder, initialize NPM by running npm init -y in the terminal.

This should have created a package.json file in your current directory.

Next, open up a code editor (like VS Code) and create an index.js file. This file will contain the code necessary to connect and access the database.

Install mongoose.js like so:

Now, with our development environment set up, we can connect to our database. Use this code:

This gist contains the boilerplate to connect to your MongoDB database

To let mongoose know where the database is hosted, we need to pass in a connection string. To get this string, navigate back to your cluster page and click the Connect button located right under the cluster name.

Click “Connect”.

On this page, you must add an IP address and create a database user. The database will only respond to requests that come from the IP you enter, so I would recommend adding your current IP.

Next, create a database user called admin. This user will be able to perform any operation on the database. Then, enter in a secure password for the user (you can also click the Autogenerate Secure Password button). Store the password somewhere as you will need it for the next step.

Add your current IP and create a database user.

After clicking “Choose a connection method,” select “Connect to your application,” since we are making an app. Copy your connection string and paste it into your code.

Make sure you are on the latest Node.js driver version and copy your connection string.

Make sure to replace <password> with the password you created and change myFirstDatabase to the name of the database you created in step one.

When you run node index.js in the terminal, you should see “MongoDB ready” logged into the console.

If this yields an error, make sure your connection string and password are correct.

Creating Models

One of the differences between the native MongoDB Node.js driver and Mongoose is that Mongoose.js requires you to create schemas/models before mutating the database.

Each collection must have a corresponding model associated with it. For example, if we are storing users in our database, we must create a user model so that Mongoose knows what fields each user has.

Create a new folder called models. In this f, make a file called User.js. This model will contain all the fields needed to create a user.

Creating a new model is easy with mongoose.js:

models/User.js
  • Models can be made using the Schema constructor.
  • Type constructors, like String, Number, and Boolean, can be used to specify the type of a field.
  • To specify additional options like if a field is required and/or default values, simply add the options in an object and remember to specify the type as well.
  • All fields are optional by default unless you set the required option to true.
  • Remember to export your Schema as a mongoose model so you can use it in other files.

Now with the schema out of the way, we can finally interact with the database!

Creating Documents

Create a new file in the main directory and name it createUser.js. Then, import the model we just created using require:

The following code will create a new user and save it into our database:

createUser.js

Notice a few things in this code snippet:

  • To create a new document, you need to create a new instance of the model and pass in the data you want to store in the document.
  • Remember to call the .save() method on your new document to make sure it gets recorded in the database.
  • .save() returns a promise so make sure you use async/await or .then() to run logic after it.

Require createUser.js in index.js by adding this line to the top of index.js:

Now, when you run index.js, you should see “User added to the database!” into the console.

Great! You just added your first document into a NoSQL database! You can see the contents of the database by clicking on “Collections” in MongoDB Atlas.

Confirm “Jimmy” has been added to the database in MongoDB Atlas.

Now, modify the fields and add another user to your database.

Add another user to the database

Notice that if you leave the email field empty, mongoose will raise an Unhandled Promise Rejection Warning.

Querying the Database

Next, we will talk about different ways you can access data from the database.

Comment out the require for createUser.js in index.js, so a new user doesn’t get created every time we run the code.

Next, create a new file, query.js, and require it in index.js just like you did with createUser.js.

Let’s take a look at how you can query a MongoDB database.

.find()

.find() is a method that you can call from an exported model, like User. The snippet below demonstrates one way you can use the .find() method:

  • Just like with createUser.js, we import the User model from the models/ directory.
  • Inside of an asynchronous function, we call the .find() method on the User model. This simply returns all of the users in our database.
  • When you run the code, you should see an array of objects containing all of the users stored in our database.

Now, let’s look at another way we can use the .find() method:

Add this snippet after the findAllUsers function.
  • This code creates another async function, but this time, it takes in an argument.
  • .find() can optionally take in an object as a parameter. This object must contain at least one key and value to specify the condition you want the returned data to meet.
  • This code, when run, will return the user whose’s firstName is equal to “Luke.”

Make sure to comment out the findAllUsers. Then, call findUserByFirstName with “Luke” as an argument.

Once you run index.js again, you should see Luke’s document logged in the terminal!

Note: find() always returns an array of documents. Use findOne() when you only need to get one document from your database.

.find() With Comparison Operators

Let’s say you need to find all the users who are older than 50. Thankfully, Mongoose.js makes it painless to use comparison operators like greater than ($gt), greater than or equal to ($gte), less than ($lt), and less than or equal to ($lte).

Add these two functions to query.js and make sure to comment out the function call to findUserByFirstName.

Note a few things about this code snippet:

  • Comparison operators always start with $
  • This snippet contains two functions: one using the $gt comparison operator and another using the $lg operator.
  • Using comparison operators is easy in MongoDB, just set the field (age in this case) equal to an object containing your comparison operator and the value you want to compare to ({ $gt: 30 })

Running your code should yield two logs: the first one containing all the users older than 50 and the second containing users younger than 50.

Your output should look similar to the log above.

Updating Documents

Next, we will dive into updating existing documents in MongoDB.

Create a new file called update.js and require it in the place of query.js.

Let’s say a user in our database has aged up, so we will need to increment their age by one.

The following snippet demonstrates this scenario:

Take note of a few things when updating documents:

  • You first need to fetch the document you want to change. This example uses the firstName field to get the document.
  • In real-world applications, you may want to query by id or another unique field.
  • After fetching the correct document, you can directly mutate the object and reassign it to any value (as long as it’s the correct data type).
  • Don’t forget to call the .save() method to save the updated document in the database.

Note: user.age++ is the same as user.age = user.age + 1

Run the code on any person in your database, and you should see that they aged up!

Jimmy (who was previously 42) aged up!

Deleting Documents

Finally, you will learn how to do the last of the four CRUD operations: deletion.

The following code sample demonstrates two ways you can delete a document from MongoDB:

Place this code in update.js and import it in index.js just like before.
  • This snippet shows two ways to delete a document in MongoDB. The first function is much shorter and doesn’t require error handling, while the second one does. Depending on your application, one function may suit you better than the other.
  • .deleteOne() takes in a parameter just like .findOne() or .find(). You can still use comparision operators and other find operators.
  • It is important to note that .deleteOne() is a method that can only be called on a model like User (notice the capitalization). On the other hand, .delete() can only be called on documents like the user variable.

Running this code should delete Luke (or any other user) from the database.

Luke is no longer in our database.

Next Steps

Great job! You have learned to do all four CRUD (Create, Read, Update, and Delete) operations using Mongoose.js! Next, I would recommend learning Express.js if you haven’t already. Express and Mongoose are a powerful combination for building REST APIs. I would also recommend diving deeper into Mongoose.js and learning about aggregation, validation, and middleware.

Here are some helpful resources to expand your knowledge:

Like what you read? Sign up for our newsletter below.

--

--

Advaith Malka
TechTalkers

I like to write about whatever wakes up my mind.