Updating Documents in MongoDB

This article is part of Robert Sheldon's continuing series on Mongo DB. To see all of the items in the series, click here.

In the previous articles this series, I demonstrated various ways to retrieve document data from a MongoDB database, using both MongoDB Shell and MongoDB Compass. In this article, my focus shifts from retrieving data to updating data, which is an essential skill to have when working with MongoDB. Whether you access the data directly in a MongoDB database or build applications that rely on the data, you should have a good foundation in how to modify a collection’s documents. This article can help you build that foundation.

MongoDB provides multiple methods for modifying the documents in a collection. In this article, I focus on two of those methods: updateOne and updateMany. The methods are fairly similar to each other except that, as their names suggest, the updateOne method can update only one document at a time, while the updateMany method can modify any number of documents.

In this article, I demonstrate how to build update statements that use these two methods to modify data. The examples are based on MongoDB Shell, rather than on how the methods might be used in a programming language such as Java or Python. On the surface, the updateOne and updateMany methods might seem fairly basic, but when you start digging deeper into them, you’ll find that they’re not quite as straightforward as they appear.

This article takes you through the basics of using these methods to modify document data. As with most MongoDB topics, covering every aspect of the two methods requires more than a single article. However, I tried to provide you with the most important information so you can start using them in your own projects.

Note: For the examples in this article, I used the same MongoDB Atlas and MongoDB Compass environments I used for the previous articles in this series. Refer to the first article for more specifics about setting up these environments. If you want to try out the examples in this article, you should create the hr database and employees collection in that database. Each section provides the test data you’ll need to try out those examples.

Updating documents in a MongoDB collection

The updateOne and updateMany methods are two of the most common methods used to update data in MongoDB. You can incorporate either one into a statement that you can then run in MongoDB Shell. The statement’s basic syntax is essentially the same for both methods, except for the method name. For example, the following syntax shows the elements that make up an updateOne statement:

The syntax might vary when used in other programming languages—as opposed to MongoDB Shell—but the basic concepts are much the same. In this case, the updateOne statement is made up of the following components:

  • db. System variable for referencing the current database and accessing the properties and methods available to the database object.
  • collection. Placeholder for the target collection. For this article, we will be using the employees collection.
  • updateOne. A method available to the collection object for updating a single document in the specified collection.
  • filter. Placeholder for the selection criteria that determine which document to update. This is similar to the filter used in a find statement. If filter returns more than one document, MongoDB applies the update only to the first document returned from the collection. An empty document ({}) means that filter returns all documents in the collection, although MongoDB still applies the update only to the first returned document. Some MongoDB documentation refers to this element as query, rather than filter.
  • update. Placeholder for the modifications that should be applied to the documents returned by filter. The above syntax shows this section enclosed in curly brackets, which indicate that you should pass in your update definition as an embedded document. However, you can instead pass in your argument as a limited aggregation pipeline, in which case, the argument is enclosed in square brackets.
  • options. Placeholder for one or more optional settings that can be included in an updateOne statement to better refine the query.

A statement that is based on an updateMany method works much the same way as the updateOne method. The only variation in the basic syntax is the method name:

The main difference between the updateOne and updateMany methods, other than their names, is the filter element. With the updateOne method, the update is applied only to the first document returned from the collection, no matter how many documents that filter returns. With the updateMany method, the update is applied to all documents that filter returns.

You’ll be able to get a better sense of how these two methods work and the differences between them as we go through the examples in this article. You’ll also see a couple of the options in action so you can get a better sense of how they work. In the meantime, you can find more information about the updateOne and updateMany methods, as well as other methods for updating data, in the MongoDB topic Update Methods.

Performing a basic update

To help you get started with the updateOne and updateMany methods, we’ll begin with a couple basic examples of how to modify documents in a collection. For this article, we’ll be using the version of MongoDB Shell embedded in the MongoDB Compass GUI. In this way, we can view our results in the main Compass interface as we update the data MongoDB Shell, making it easier to see what has changed.

If you plan to try out these examples for yourself, make sure to first create the hr database and employees collection. You should then open the collection in the main Compass window so you can easily see your results as you work through the examples.

After you’ve set up your database and collection, go to MongoDB Shell and run the following use statement to change the context to the hr database:

Next, you’ll need to add several documents to the collection so you have something to update. For this, you can use an insertMany method. The method is available to the collection object for adding multiple documents to a collection. The following statement uses the method to add three documents to the employees collection:

The documents are passed into the insertMany method as an array of embedded documents. Although these are very simple documents, they’re enough to demonstrate how to update data.

To run the insertMany statement, copy and paste it to the MongoDB Shell command prompt and then press Enter. MongoDB should return a message indicating that the three documents have been added. Next, go to the Documents tab of the main Compass window and click the refresh button in the tab’s upper right corner. The tab should now display the three documents, as shown in the following figure.

With the data in place, you’re now ready to try out your first update statement. In the following example, the updateOne method identifies the target document and changes the value of the title field to Brand Manager:

The statement includes two embedded documents, which define the method’s filter and update elements, respectively:

  • The filter element specifies that only the document with an _id value of 103 should be updated.
  • The update element uses the $set operator to assign a new value to a field. In this case, the operator sets the value of the title field to Brand Manager. The field name and its value are enclosed in curly brackets and separated by a colon.

When you run this statement, MongoDB Shell returns the following message, which indicates that one document matched the filter criteria and one document was modified:

If you return to the Documents tab of the main window and click the refresh button, the Compass GUI should now display the following results, which show that the title value in the third document has been updated.

Now let’s look at an example that uses the updateMany method to modify documents. The following statement changes the value of the department field to R&D in the target documents:

As with the previous example, the statement includes two embedded documents for defining the filter and update elements:

  • The filter element specifies that only documents with a department value of Development should be updated.
  • The update element uses the $set operator to set the department value to R&D.

When you run this statement, MongoDB Shell returns the following message, which indicates that two documents match the search criteria and two documents have been modified:

If you once again refresh the Documents tab of the main window, Compass should now display the following results, which show that the department value in the first two documents has been updated.

As you can see, using the updateOne and updateMany methods to perform basic modifications on a document is fairly straightforward, and the two methods work much the same. You must first define the filter element, followed by the update element. That said, there is much more you can do with both of these methods.

Performing an Upsert

As I mentioned earlier in the article, the updateOne and updateMany methods let you specify optional settings to better refine your query. One of these options is upsert, which controls how an updateOne or updateMany statement behaves if no documents match the filter criteria.

The upsert option takes a Boolean value, either true or false. When the option is set to true, the statement performs one of the following actions:

  • If filter returns a match, the statement updates the target document or documents.
  • If filter returns no matches, the statement inserts a new document, based on the filter and update elements.

If the upsert option is instead set to false, the statement does not insert a new document into the collection, even if filter returns no matches. This is the default setting and how an update statement behaves when the option is not specified.

Before we look at an example that uses the upsert option, let’s delete the existing documents in the employees collection so we’re starting with a clean slate. You can delete all the documents at once by running the following deleteMany statement:

Because the deleteMany statement does not specify a filter criteria—instead using only an empty set of curly brackets—the statement will delete all documents in the collection. This is a handy statement to remember when you’re learning about MongoDB or want to clean up your development or test environments. However, use extreme caution when using this statement in a production environment.

After you delete the collection’s documents, you can run the following insertMany statement to add the original documents back into the collection:

Now let’s try out the upsert option when updating a document. The following updateOne statement attempts to update a document with an _id value of 104:

Unlike the previous examples, the method now includes three embedded documents:

  • The filter element specifies that only the document with an _id value of 104 should be updated.
  • The update element uses the $set operator to set the name, title , and department fields to the values Casey, Copy Writer, and Marketing, respectively.
  • The upsert element sets the upsert option to true. Notice that the option is added as an embedded document, just like the filter and update elements.

When you run the updateOne statement, MongoDB Shell returns the following message:

The message indicates that one document has been upserted and the ID for that document is 104. It also indicates that there were no matched documents. If you once again refresh the Documents tab of the main window, the Compass GUI should display the results shown in the following figure, which now include a fourth document.

MongoDB added the fourth document to the collection because no documents matched the filter criteria in the original query. An updateMany statement works much the same way, as shown in the following example:

Like the previous example, this statement includes three embedded documents:

  • The filter element specifies that only documents with a name value of Jesse and a title value of Senior Developer should be updated.
  • The update element uses the $set operator to set the department value to R&D.
  • The upsert element sets the upsert option to true.

When you run the updateMany statement, MongoDB Shell returns the following message:

In this case, the message indicates that one document has been upserted and that the document’s ID is a GUID, unlike the simple integers used for the other documents. MongoDB generated the _id value automatically because no value had been specified in the filter or update element. When you refresh the Documents tab, the Compass GUI now shows the following documents:

As you can see, a fifth document was added to the collection, and its _id value is a GUID. Because the filter element in the updateMany statement did not return any matches, MongoDB inserted a new document using the information from the filter and update elements.

Updating an embedded document

In the previous examples, the statements updated simple string fields that required you only to specify the field name and new value. The process works much the same for embedded documents, except that you must qualify the names of the subfields to ensure the data gets modified as expected.

To see how this works, first delete the documents in the employees collection, and then run the following insertMany statement:

The statement defines three documents that each contain the position field. The field’s value is an embedded document that includes the title and department subfields. Now let’s try to update one of the subfields, using the following updateOne statement:

The filter element specifies that only the document with an _id value of 103 should be updated. This is followed by the update element, which uses the $set operator to set the title value to Brand Manager. Notice that you must qualify the subfield name by preceding it with the position field name, followed by a period. In this way, MongoDB knows exactly where to find the target subfield.

After you run the statement, you can refresh the Documents tab to review the results, which are shown in the following figure.

Notice that the title subfield has been updated in the third document. As this example demonstrates, you must qualify the field names in embedded documents when referencing them in an update element. This is also true if you specify an embedded field in the filter element, as in the following updateMany statement:

This time, the filter element specifies that only documents with a position.department value of Development should be updated. Only two documents meet this criteria. The update element then uses the $set operator to set their position.department value to R&D. After you run the statement, you can again refresh the Documents tab to review the results, which are shown in the following figure.

That’s all there is to working with embedded documents. That main point to remember is that you need to qualify the field names when they come from an embedded document.

Updating an array

Updating an array value is a little trickier than with an embedded document. For this, you’ll need to use the arrayFilters option, which I’ll demonstrate shortly. But first, you should again delete the documents in the employees collection and this time run the following insertMany statement:

The statement adds three documents to the collection. Each document includes the skills array, which contains several string values describing the employee’s skills.

Now let’s look at how to modify the array. Suppose you want to update a skill in one of the documents, in this case, the one with an _id value of 101. Your goal is to change the PHP value in the skills array to JavaScript. For this, you can run the following updateOne statement:

As you can see, the updateOne method defines three elements:

  • The filter element specifies that only the document with an _id value of 101 should be updated.
  • The update element uses the $set operator to specify that a value in the skills array should be changed to JavaScript. The value to be changed is represented by the skill variable, which is constructed as an identifier operator. An identifier operator is an element enclosed in square brackets and preceded by a dollar sign, all of which is then tagged onto the array name.
  • The arrayFilters element essentially defines the skill variable by assigning the old value, PHP, to the variable. In this way, the variable can be used in the update element to indicate which value should be changed within the array. Note that the variable (identifier) name must begin with a lowercase letter and can contain only alphanumeric characters.

After you run the updateOne statement, you can again refresh the Documents tab and review the results, which are shown in the following figure. As you can see, the original array value, PHP, has been replaced with JavaScript.

You can also use the arrayFilters option in an updateMany statement, once again specifying a variable that identifies the value to be changed. For example, the follow statement updates the documents that contain the value Csharp in the skills array:

As in the previous example, the statement includes three elements:

  • The filter element specifies that the documents must contain the value Csharp in the skills array.
  • The update element changes the array value Csharp to C#, using the skill variable to reference the original value.
  • The arrayFilters element assigns the value Csharp to the skill variable so it can be used in the update element.

The statement updates two documents. You can confirm this by again refreshing the Documents tab in the main Compass window. The following figure shows the updated documents.

Updating an array value is fairly straightforward once you figure out how an identifier operator works and how to apply the arrayFilters option. To this end, you might find it useful to review the MongoDB topic $[<identifier>] to get a better sense of how to use both an identifier operator and the arrayFilters option.

Updating with an aggregation pipeline

The examples up to this point have used an embedded document for the update element, which defines the modifications that should be applied to the filtered documents. However, you can instead specify an aggregation pipeline for the update element, using any of the following three stages:

  • The $addFields stage (or its alias $set)—adds fields to the documents in the pipeline.
  • The $project stage (or its alias $unset)—reshapes the fields in the pipeline documents.
  • The $replaceRoot stage (or its alias $replaceWith)—replaces each document in the pipeline with the specified embedded document.

An aggregation pipeline can provide you with more flexibility when modifying your documents, compared to the statements we’ve created so far. To see how this works, first delete the documents in the employees collection, and then run the following insertMany statement, which creates three simple documents:

Next, we’ll create an insertMany statement that restructures each document and adds a calculated field, as shown in the following code:

The statement begins by defining the filter element as an empty document, which means that the update will be applied to all documents in the collection. The filter element is followed by an update element that defines an aggregation pipeline, as indicated by the square brackets. The pipeline includes the following three stages:

  • The first $set stage (which is an alias for $addFields) adds a field named position. The field’s value is an embedded document that contains the title and department subfields. The original title and department fields provide the values for the new subfields. This is done by referencing the original fields and preceding their names with a dollar sign.
  • The second $set stage creates a subfield named division within the position field. The value of the subfield is determined by the $switch operator, which is used to create a conditional case expression. The expression defines the branches array and its four embedded documents. Each document uses the case operator to specify a value for the division subfield, based on a value in the department subfield. For example, the first embedded document specifies that the division subfield should be assigned the value Eastern if the department value is Development. The branches array is then followed by a default element that designates Central as the default value if no conditions are met.
  • The final $unset stage specifies that the original title and department fields should be removed from each document. These fields are no longer needed because their values have been reassigned to the position subfields in the first $set stage.

After you define you’re statement, you can run it in MongoDB Shell and view the results on the Documents tab. The following figure shows the collection’s documents after they’ve been updated and the tab refreshed.

As you can see, each document now contains the position field and its value, which is an embedded document. The embedded document includes the original title and department fields, along with the new division field.

Although we were working with very simple documents for this example, it should still give you a sense of how useful it might be to include an aggregation pipeline in your updateOne and updateMany statements, despite having only three stages to work with.

Getting started with MongoDB updates

The ability to update data is one of the core skills you should have when working with MongoDB. To this end, the updateOne and updateMany methods provide a good place to start learning how to modify data. However, they’re not the only methods available. For example, MongoDB also supports the replaceOne, findOneAndReplace, findOneAndUpdate, and findAndModify methods, any of which you might find useful at times. In addition, you can update data directly in the Compass GUI by modifying a document’s individual values.

Despite the various options available in MongoDB for updating data, the updateOne and updateMany methods will go a long way in helping you get started with modifying data. You might find it useful to check out the MongoDB documentation that covers these methods, as well as other methods for updating data. When it comes to modifying data, however, you must proceed cautiously to ensure you don’t make incorrect changes, especially in a production environment. The better you understand how to update data in a MongoDB database, the less likely you are to inadvertently wipe out an entire collection of documents.