MongoDB: Updates with Aggregation Pipeline

Rofl Facts
7 min readNov 25, 2023

--

You can utilise the aggregate pipeline for update operations starting with MongoDB 4.2. To perform updates in Drivers, MongoDB Atlas, MongoDB Compass, or MongoDB Shell, you can create and run aggregation pipelines.

The following steps can be included in the aggregation pipeline with the update operations:

A more expressive update statement, such as one that expresses conditional updates depending on current field values or updates one field using the value of another field, is possible when using the aggregate pipeline.

Create an Update Aggregation Pipeline in Atlas

The MongoDB Atlas UI allows you to create an aggregation pipeline for updating. In the MongoDB Atlas UI, you need to have the Project Data Access Read Only role or above in order to design and run aggregation pipelines.

1. Access the Aggregation Pipeline Builder.

a. Decide which database to use for the gathering.
The database’s collections are listed in the main panel and Namespaces on the left.

b. Choose the collection.
Choose the collection located in the main panel or on the left. The Find, Indexes, and Aggregation views are shown in the main panel.

c. Choose the view for aggregation.
Atlas shows an empty aggregation pipeline when you initially launch the Aggregation view.

2. Create an aggregation pipeline to perform updates.

a. Choose a step for aggregation.
From the Select drop-down menu in the bottom-left panel, choose an aggregate stage.

The stage’s enablement is controlled by the toggle to the right of the drop-down menu.

Use one of the following stages to carry out updates using an aggregation:

b. Complete the stage of aggregation.
To complete your step, enter the relevant values. Syntactic recommendations for the step you have selected are provided by the pipeline builder if you have activated Comment Mode.

Based on the outcomes of the current stage, Atlas refreshes the preview documents on the right as you make changes to your stage.

See the samples on this page for ideas of what you could include in your aggregate stage.

As needed, add phases. See Create an Aggregation Pipeline for additional details on setting up aggregation pipelines in Atlas.

3. Export the aggregation pipeline.

a. Select “Export to Language.”
This button is located at the pipeline builder’s top.

b. Choose the export language that you want.
Choose the language you want to export Pipeline To.

Your pipeline is shown in MongoDB Shell syntax in the My Pipeline pane on the left. To run your pipeline in the MongoDB Shell, simply copy this.

Your pipeline is shown in the chosen language in the pane on the right. Make your choice of language.

c. Choose alternatives if you’d like.
If desired: To include the necessary import statements for the chosen language, check the Include Import Statements box.

(Optional): To add driver-specific code to:, select the Include Driver Syntax option.

  • Set up the client first.
  • Indicate the collection and database.
  • Execute the process of aggregation.

d. Make a duplicate of the pipeline.
To copy the pipeline for the chosen language to your clipboard, click the Copy button located at the top-right corner of the pipeline. The copied pipeline should be pasted into your programme.

Examples

The aggregate pipeline stages $set, $replaceRoot, and $addFields can be used to execute updates, as seen in the examples below.

updateOne with $set

Make a sample student collection (insert operations will create the collection if it doesn’t already exist):

db.students.insertMany( [
{ _id: 1, test1: 95, test2: 92, test3: 90, modified: new Date("01/05/2020") },
{ _id: 2, test1: 98, test2: 100, test3: 102, modified: new Date("01/05/2020") },
{ _id: 3, test1: 95, test2: 110, modified: new Date("01/04/2020") }
] )

To confirm, verify the collection:

db.students.find()

The db.collection that follows.An aggregate pipeline is used by the updateOne() method to update the document with _id: 3:

db.students.updateOne( { _id: 3 }, [ { $set: { "test3": 98, modified: "$$NOW"} } ] )

The pipeline is composed of a $set stage that adds the test3 field to the document (with a value of 98) and updates the changed field with the current datetime. For the current datetime, the operation makes use of the aggregation variable NOW. Prefix the variable with $$ and enclose it in quotations to gain access to it.

You can query the collection to confirm the update:

db.students.find().pretty()

updateMany with $replaceRoot and $set

Make an example students2 collection (insert operations will construct the collection if it doesn’t already exist):

db.students2.insertMany( [
{ "_id" : 1, quiz1: 8, test2: 100, quiz2: 9, modified: new Date("01/05/2020") },
{ "_id" : 2, quiz2: 5, test1: 80, test2: 89, modified: new Date("01/05/2020") },
] )

To confirm, verify the collection:

db.students2.find()

The db.collection that follows.refreshTo update the updated field and standardise the fields for the documents (i.e., all documents in the collection should have the same fields), the Many() method employs an aggregate pipeline:

db.students2.updateMany( {},
[
{ $replaceRoot: { newRoot:
{ $mergeObjects: [ { quiz1: 0, quiz2: 0, test1: 0, test2: 0 }, "$$ROOT" ] }
} },
{ $set: { modified: "$$NOW"} }
]
)

In particular, the pipeline is made up of:

  • a $mergeObjects expression in a $replaceRoot stage to set the default values for the test1, test2, and quiz fields. The current document under modification is referenced by the aggregate variable ROOT. Prefix the variable with $$ and enclose it in quotations to gain access to it. The default values will be superseded by the current document fields.
  • a $set stage to update the datetime of the modified field to the present one. For the current datetime, the operation makes use of the aggregation variable NOW. Prefix the variable with $$ and enclose it in quotations to gain access to it.

You can query the collection to confirm the update:

db.students2.find()

updateMany with $set

Make a sample students3 collection (insert operations will construct the collection if it doesn’t already exist):

db.students3.insertMany( [
{ "_id" : 1, "tests" : [ 95, 92, 90 ], "modified" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 2, "tests" : [ 94, 88, 90 ], "modified" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 3, "tests" : [ 70, 75, 82 ], "modified" : ISODate("2019-01-01T00:00:00Z") }
] );

To confirm, contact the collection:

db.students3.find()

The db.collection that follows refresh the Many() operation updates the documents with the determined letter grade and grade average using an aggregation pipeline.

db.students3.updateMany(
{ },
[
{ $set: { average : { $trunc: [ { $avg: "$tests" }, 0 ] }, modified: "$$NOW" } },
{ $set: { grade: { $switch: {
branches: [
{ case: { $gte: [ "$average", 90 ] }, then: "A" },
{ case: { $gte: [ "$average", 80 ] }, then: "B" },
{ case: { $gte: [ "$average", 70 ] }, then: "C" },
{ case: { $gte: [ "$average", 60 ] }, then: "D" }
],
default: "F"
} } } }
]
)

In particular, the pipeline is made up of:

  • a $set step to update the modified field with the current datetime and compute the truncated average value of the tests array members. The step uses the $avg and $trunc expressions to compute the truncated average. For the current datetime, the operation makes use of the aggregation variable NOW. Prefix the variable with $$ and enclose it in quotations to gain access to it.
  • a $set stage that uses the $switch expression to add the grade field based on the average.

You can query the collection to confirm the update:

db.students3.find()

updateOne with $set

Make an example students4 collection (insert operations will construct the collection if it doesn’t already exist):

db.students4.insertMany( [
{ "_id" : 1, "quizzes" : [ 4, 6, 7 ] },
{ "_id" : 2, "quizzes" : [ 5 ] },
{ "_id" : 3, "quizzes" : [ 10, 10, 10 ] }
] )

To confirm, contact the collection:

db.students4.find()

The db.collection that follows an aggregate pipeline is used by the updateOne() method to append quiz results to the document with _id: 2:

db.students4.updateOne( { _id: 2 },
[ { $set: { quizzes: { $concatArrays: [ "$quizzes", [ 8, 6 ] ] } } } ]
)

You can query the collection to confirm the update:

db.students4.find()

updateMany with $addFields

If the collection does not already exist, insert operations will create it. Otherwise, establish an example temperatures collection with temperatures in Celsius:

db.temperatures.insertMany( [
{ "_id" : 1, "date" : ISODate("2019-06-23"), "tempsC" : [ 4, 12, 17 ] },
{ "_id" : 2, "date" : ISODate("2019-07-07"), "tempsC" : [ 14, 24, 11 ] },
{ "_id" : 3, "date" : ISODate("2019-10-30"), "tempsC" : [ 18, 6, 8 ] }
] )

To confirm, contact the collection:

db.temperatures.find()

The db.collection that follows refresh the Many() procedure updates the pages with the associated temperatures in Fahrenheit using an aggregate pipeline:

db.temperatures.updateMany( { },
[
{ $addFields: { "tempsF": {
$map: {
input: "$tempsC",
as: "celsius",
in: { $add: [ { $multiply: ["$$celsius", 9/5 ] }, 32 ] }
}
} } }
]
)

The pipeline comprises a $addFields stage that adds a new array field tempsF with the Fahrenheit temperatures. The stage uses the $map expression with the $add and $multiply expressions to convert each Celsius temperature in the tempsC array to a Fahrenheit value.

You can query the collection to confirm the update:

db.temperatures.find()

--

--