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.
--
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.
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?
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).
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.
When you see the screen shown below, give your project a name.
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.
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.
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.
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.
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.
npm init -y
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:
npm i mongoose
Now, with our development environment set up, we can connect to our database. Use this code:
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.
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.
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 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 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:
const User = require(“./models/User”);
The following code will create a new user and save it into our database:
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:
require(“./createUser”);
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.
Now, modify the fields and add another user to your 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:
- 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.
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 asuser.age = user.age + 1
Run the code on any person in your database, and you should see that they 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:
- 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.
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.