EventGet 50% off your ticket to MongoDB.local NYC on May 2. Use code Web50!Learn more >>
MongoDB Developer
JavaScript
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Languageschevron-right
JavaScriptchevron-right

MongoDB and Node.js Tutorial - CRUD Operations

Lauren Schaefer17 min read • Published Feb 04, 2022 • Updated Aug 22, 2023
MongoDBJavaScript
Facebook Icontwitter iconlinkedin icon
Rate this quickstart
star-empty
star-empty
star-empty
star-empty
star-empty
QuickStart Node.js Logo
In the first post in this series, I walked you through how to connect to a MongoDB database from a Node.js script, retrieve a list of databases, and print the results to your console. If you haven't read that post yet, I recommend you do so and then return here.
This post uses MongoDB 4.4, MongoDB Node.js Driver 3.6.4, and Node.js 14.15.4.
Click here to see a previous version of this post that uses MongoDB 4.0, MongoDB Node.js Driver 3.3.2, and Node.js 10.16.3.
Now that we have connected to a database, let's kick things off with the CRUD (create, read, update, and delete) operations.
If you prefer video over text, I've got you covered. Check out the video in the section below. :-)
Get started with an M0 cluster on Atlas today. It's free forever, and it's the easiest way to try out the steps in this blog series.
Here is a summary of what we'll cover in this post:

Learn by Video

I created the video below for those who prefer to learn by video instead of text. You might also find this video helpful if you get stuck while trying the steps in the text-based instructions below.
Here is a summary of what the video covers:
  • How to connect to a MongoDB database hosted on MongoDB Atlas from inside of a Node.js script (01:00)
  • How MongoDB stores data in documents and collections (instead of rows and tables) (08:22)
  • How to create documents using insertOne() and insertMany() (11:47)
  • How to read documents using findOne() and find() (17:16)
  • How to update documents using updateOne() with and without upsert as well as updateMany() (24:46​)
  • How to delete documents using deleteOne() and deleteMany() (35:58)
Below are the links I mentioned in the video.

How MongoDB Stores Data

Before we go any further, let's take a moment to understand how data is stored in MongoDB.
MongoDB stores data in BSON documents. BSON is a binary representation of JSON (JavaScript Object Notation) documents. When you read MongoDB documentation, you'll frequently see the term "document," but you can think of a document as simply a JavaScript object. For those coming from the SQL world, you can think of a document as being roughly equivalent to a row.
MongoDB stores groups of documents in collections. For those with a SQL background, you can think of a collection as being roughly equivalent to a table.
Every document is required to have a field named _id. The value of _id must be unique for each document in a collection, is immutable, and can be of any type other than an array. MongoDB will automatically create an index on _id. You can choose to make the value of _id meaningful (rather than a somewhat random ObjectId) if you have a unique value for each document that you'd like to be able to quickly search.
In this blog series, we'll use the sample Airbnb listings dataset. The sample_airbnb database contains one collection: listingsAndReviews. This collection contains documents about Airbnb listings and their reviews.
Let's take a look at a document in the listingsAndReviews collection. Below is part of an Extended JSON representation of a BSON document:
For more information on how MongoDB stores data, see the MongoDB Back to Basics Webinar that I co-hosted with Ken Alger.

Setup

To make following along with this blog post easier, I've created a starter template for a Node.js script that accesses an Atlas cluster.
  1. Download a copy of template.js.
  2. Open template.js in your favorite code editor.
  3. Update the Connection URI to point to your Atlas cluster. If you're not sure how to do that, refer back to the first post in this series.
  4. Save the file as crud.js.
You can run this file by executing node crud.js in your shell. At this point, the file simply opens and closes a connection to your Atlas cluster, so no output is expected. If you see DeprecationWarnings, you can ignore them for the purposes of this post.

Create

Now that we know how to connect to a MongoDB database and we understand how data is stored in a MongoDB database, let's create some data!

Create One Document

Let's begin by creating a new Airbnb listing. We can do so by calling Collection's insertOne(). insertOne() will insert a single document into the collection. The only required parameter is the new document (of type object) that will be inserted. If our new document does not contain the _id field, the MongoDB driver will automatically create an _id for the document.
Our function to create a new listing will look something like the following:
We can call this function by passing a connected MongoClient as well as an object that contains information about a listing.
The output would be something like the following:
Note that since we did not include a field named _id in the document, the MongoDB driver automatically created an _id for us. The _id of the document you create will be different from the one shown above. For more information on how MongoDB generates _id, see Quick Start: BSON Data Types - ObjectId.
If you're not a fan of copying and pasting, you can get a full copy of the code above in the Node.js Quick Start GitHub Repo.

Create Multiple Documents

Sometimes you will want to insert more than one document at a time. You could choose to repeatedly call insertOne(). The problem is that, depending on how you've structured your code, you may end up waiting for each insert operation to return before beginning the next, resulting in slow code.
Instead, you can choose to call Collection's insertMany(). insertMany() will insert an array of documents into your collection.
One important option to note for insertMany() is ordered. If ordered is set to true, the documents will be inserted in the order given in the array. If any of the inserts fail (for example, if you attempt to insert a document with an _id that is already being used by another document in the collection), the remaining documents will not be inserted. If ordered is set to false, the documents may not be inserted in the order given in the array. MongoDB will attempt to insert all of the documents in the given array—regardless of whether any of the other inserts fail. By default, ordered is set to true.
Let's write a function to create multiple Airbnb listings.
We can call this function by passing a connected MongoClient and an array of objects that contain information about listings.
Note that every document does not have the same fields, which is perfectly OK. (I'm guessing that those who come from the SQL world will find this incredibly uncomfortable, but it really will be OK 😊.) When you use MongoDB, you get a lot of flexibility in how to structure your documents. If you later decide you want to add schema validation rules so you can guarantee your documents have a particular structure, you can.
The output of calling createMultipleListings() would be something like the following:
Just like the MongoDB Driver automatically created the _id field for us when we called insertOne(), the Driver has once again created the _id field for us when we called insertMany().
If you're not a fan of copying and pasting, you can get a full copy of the code above in the Node.js Quick Start GitHub Repo.

Read

Now that we know how to create documents, let's read one!

Read One Document

Let's begin by querying for an Airbnb listing in the listingsAndReviews collection by name.
We can query for a document by calling Collection's findOne(). findOne() will return the first document that matches the given query. Even if more than one document matches the query, only one document will be returned.
findOne() has only one required parameter: a query of type object. The query object can contain zero or more properties that MongoDB will use to find a document in the collection. If you want to query all documents in a collection without narrowing your results in any way, you can simply send an empty object.
Since we want to search for an Airbnb listing with a particular name, we will include the name field in the query object we pass to findOne():
Our function to find a listing by querying the name field could look something like the following:
We can call this function by passing a connected MongoClient as well as the name of a listing we want to find. Let's search for a listing named "Infinite Views" that we created in an earlier section.
The output should be something like the following.
Note that the _id of the document in your database will not match the _id in the sample output above.
If you're not a fan of copying and pasting, you can get a full copy of the code above in the Node.js Quick Start GitHub Repo.

Read Multiple Documents

Now that you know how to query for one document, let's discuss how to query for multiple documents at a time. We can do so by calling Collection's find().
Similar to findOne(), the first parameter for find() is the query object. You can include zero to many properties in the query object.
Let's say we want to search for all Airbnb listings that have minimum numbers of bedrooms and bathrooms. We could do so by making a call like the following:
As you can see above, we have two properties in our query object: one for bedrooms and one for bathrooms. We can leverage the $gte comparison query operator to search for documents that have bedrooms greater than or equal to a given number. We can do the same to satisfy our minimum number of bathrooms requirement. MongoDB provides a variety of other comparison query operators that you can utilize in your queries. See the official documentation for more details.
The query above will return a Cursor. A Cursor allows traversal over the result set of a query.
You can also use Cursor's functions to modify what documents are included in the results. For example, let's say we want to sort our results so that those with the most recent reviews are returned first. We could use Cursor's sort() function to sort the results using the last_review field. We could sort the results in descending order (indicated by passing -1 to sort()) so that listings with the most recent reviews will be returned first. We can now update our existing query to look like the following.
The above query matches 192 documents in our collection. Let's say we don't want to process that many results inside of our script. Instead, we want to limit our results to a smaller number of documents. We can chain another of sort()'s functions to our existing query: limit(). As the name implies, limit() will set the limit for the cursor. We can now update our query to only return a certain number of results.
We could choose to iterate over the cursor to get the results one by one. Instead, if we want to retrieve all of our results in an array, we can call Cursor's toArray() function. Now our code looks like the following:
Now that we have our query ready to go, let's put it inside an asynchronous function and add functionality to print the results.
We can call this function by passing a connected MongoClient as well as an object with properties indicating the minimum number of bedrooms, the minimum number of bathrooms, and the maximum number of results.
If you've created the documents as described in the earlier section, the output would be something like the following:
If you're not a fan of copying and pasting, you can get a full copy of the code above in the Node.js Quick Start GitHub Repo.

Update

We're halfway through the CRUD operations. Now that we know how to create and read documents, let's discover how to update them.

Update One Document

Let's begin by updating a single Airbnb listing in the listingsAndReviews collection.
We can update a single document by calling Collection's updateOne(). updateOne() has two required parameters:
  1. filter (object): the Filter used to select the document to update. You can think of the filter as essentially the same as the query param we used in findOne() to search for a particular document. You can include zero properties in the filter to search for all documents in the collection, or you can include one or more properties to narrow your search.
  2. update (object): the update operations to be applied to the document. MongoDB has a variety of update operators you can use such as $inc, $currentDate, $set, and $unset among others. See the official documentation for a complete list of update operators and their descriptions.
updateOne() also has an optional options param. See the updateOne() docs for more information on these options.
updateOne() will update the first document that matches the given query. Even if more than one document matches the query, only one document will be updated.
Let's say we want to update an Airbnb listing with a particular name. We can use updateOne() to achieve this. We'll include the name of the listing in the filter param. We'll use the $set update operator to set new values for new or existing fields in the document we are updating. When we use $set, we pass a document that contains fields and values that should be updated or created. The document that we pass to $set will not replace the existing document; any fields that are part of the original document but not part of the document we pass to $set will remain as they are.
Our function to update a listing with a particular name would look like the following:
Let's say we want to update our Airbnb listing that has the name "Infinite Views." We created this listing in an earlier section.
We can call updateListingByName() by passing a connected MongoClient, the name of the listing, and an object containing the fields we want to update and/or create.
Executing this command results in the following output.
Now our listing has an updated number of bedrooms and beds.
If you're not a fan of copying and pasting, you can get a full copy of the code above in the Node.js Quick Start GitHub Repo.

Upsert One Document

One of the options you can choose to pass to updateOne() is upsert. Upsert is a handy feature that allows you to update a document if it exists or insert a document if it does not.
For example, let's say you wanted to ensure that an Airbnb listing with a particular name had a certain number of bedrooms and bathrooms. Without upsert, you'd first use findOne() to check if the document existed. If the document existed, you'd use updateOne() to update the document. If the document did not exist, you'd use insertOne() to create the document. When you use upsert, you can combine all of that functionality into a single command.
Our function to upsert a listing with a particular name can be basically identical to the function we wrote above with one key difference: We'll pass {upsert: true} in the options param for updateOne().
Let's say we aren't sure if a listing named "Cozy Cottage" is in our collection or, if it does exist, if it holds old data. Either way, we want to ensure the listing that exists in our collection has the most up-to-date data. We can call upsertListingByName() with a connected MongoClient, the name of the listing, and an object containing the up-to-date data that should be in the listing.
If the document did not previously exist, the output of the function would be something like the following:
We have a new document in the listingsAndReviews collection:
If we discover more information about the "Cozy Cottage" listing, we can use upsertListingByName() again.
And we would see the following output.
Now our document has a new field named "beds."
If you're not a fan of copying and pasting, you can get a full copy of the code above in the Node.js Quick Start GitHub Repo.

Update Multiple Documents

Sometimes you'll want to update more than one document at a time. In this case, you can use Collection's updateMany(). Like updateOne(), updateMany() requires that you pass a filter of type object and an update of type object. You can choose to include options of type object as well.
Let's say we want to ensure that every document has a field named property_type. We can use the $exists query operator to search for documents where the property_type field does not exist. Then we can use the $set update operator to set the property_type to "Unknown" for those documents. Our function will look like the following.
We can call this function with a connected MongoClient.
Below is the output from executing the previous command.
Now our "Cozy Cottage" document and all of the other documents in the Airbnb collection have the property_type field.
Listings that contained a property_type before we called updateMany() remain as they were. For example, the "Spectacular Modern Uptown Duplex" listing still has property_type set to Apartment.
If you're not a fan of copying and pasting, you can get a full copy of the code above in the Node.js Quick Start GitHub Repo.

Delete

Now that we know how to create, read, and update documents, let's tackle the final CRUD operation: delete.

Delete One Document

Let's begin by deleting a single Airbnb listing in the listingsAndReviews collection.
We can delete a single document by calling Collection's deleteOne(). deleteOne() has one required parameter: a filter of type object. The filter is used to select the document to delete. You can think of the filter as essentially the same as the query param we used in findOne() and the filter param we used in updateOne(). You can include zero properties in the filter to search for all documents in the collection, or you can include one or more properties to narrow your search.
deleteOne() also has an optional options param. See the deleteOne() docs for more information on these options.
deleteOne() will delete the first document that matches the given query. Even if more than one document matches the query, only one document will be deleted. If you do not specify a filter, the first document found in natural order will be deleted.
Let's say we want to delete an Airbnb listing with a particular name. We can use deleteOne() to achieve this. We'll include the name of the listing in the filter param. We can create a function to delete a listing with a particular name.
Let's say we want to delete the Airbnb listing we created in an earlier section that has the name "Cozy Cottage." We can call deleteListingsByName() by passing a connected MongoClient and the name "Cozy Cottage."
Executing the command above results in the following output.
If you're not a fan of copying and pasting, you can get a full copy of the code above in the Node.js Quick Start GitHub Repo.

Deleting Multiple Documents

Sometimes you'll want to delete more than one document at a time. In this case, you can use Collection's deleteMany(). Like deleteOne(), deleteMany() requires that you pass a filter of type object. You can choose to include options of type object as well.
Let's say we want to remove documents that have not been updated recently. We can call deleteMany() with a filter that searches for documents that were scraped prior to a particular date. Our function will look like the following.
To delete listings that were scraped prior to February 15, 2019, we can call deleteListingsScrapedBeforeDate() with a connected MongoClient and a Date instance that represents February 15.
Executing the command above will result in the following output.
Now only recently scraped documents are in our collection.
If you're not a fan of copying and pasting, you can get a full copy of the code above in the Node.js Quick Start GitHub Repo.

Wrapping Up

We covered a lot today! Let's recap.
We began by exploring how MongoDB stores data in documents and collections. Then we learned the basics of creating, reading, updating, and deleting data.
Continue on to the next post in this series, where we'll discuss how you can analyze and manipulate data using the aggregation pipeline.
Comments? Questions? We'd love to chat with you in the MongoDB Community.

Facebook Icontwitter iconlinkedin icon
Rate this quickstart
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Tutorial

Real Time Data in a React JavaScript Front-End with Change Streams


Oct 04, 2022 | 6 min read
Tutorial

Using Expo and Realm React Native with expo-dev-client


Aug 26, 2022 | 3 min read
Tutorial

Build a Totally Serverless REST API with MongoDB Atlas


Feb 03, 2023 | 5 min read
Code Example

myLeG


Jul 07, 2022 | 1 min read
Table of Contents