Starting in MongoDB 4.2, you can use the aggregation pipeline for update operations. You can build and execute aggregation pipelines to perform updates in MongoDB Atlas, MongoDB Compass, MongoDB Shell, or Drivers.
With the update operations, the aggregation pipeline can consist of the following stages:
Using the aggregation pipeline allows for a more expressive update statement, such as expressing conditional updates based on current field values or updating one field using the value of another field(s).
Create an Update Aggregation Pipeline in Atlas
You can use the MongoDB Atlas UI to build an aggregation pipeline to perform
updates. To create and execute aggregation pipelines in the
MongoDB Atlas UI, you must have the
Project Data Access Read Only role or higher.
Create an aggregation pipeline to perform updates.
Export the aggregation pipeline.
Select your desired export language.
In the Export Pipeline To menu, select your desired language.
The My Pipeline pane on the left displays your pipeline in MongoDB Shell syntax. You can copy this directly to execute your pipeline in the MongoDB Shell.
The pane on the right displays your pipeline in the selected language. Select your preferred language.
Select options, if desired.
(Optional): Check the Include Import Statements option to include the required import statements for the language selected.
(Optional): Check the Include Driver Syntax option to include Driver-specific code to:
Initialize the client
Specify the database and collection
Perform the aggregation operation
Examples
The following examples demonstrate how to use the aggregation pipeline
stages $set, $replaceRoot, and $addFields to perform updates.
updateOne with $set
Create an example students collection (if the collection does
not currently exist, insert operations will create the collection):
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 verify, query the collection:
db.students.find()
The following db.collection.updateOne() operation uses an
aggregation pipeline to update the document with _id: 3:
db.students.updateOne( { _id: 3 }, [ { $set: { "test3": 98, modified: "$$NOW"} } ] )
Specifically, the pipeline consists of a $set stage
which adds the test3 field (and sets its value to 98) to the
document and sets the modified field to the current datetime.
The operation uses the aggregation variable NOW for the
current datetime. To access the variable, prefix with $$ and enclose
in quotes.
To verify the update, you can query the collection:
db.students.find().pretty()
updateMany with $replaceRoot and $set
Create an example students2 collection (if the collection does not
currently exist, insert operations will create the collection):
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 verify, query the collection:
db.students2.find()
The following
db.collection.updateMany() operation uses an aggregation
pipeline to standardize the fields for the documents (i.e. documents
in the collection should have the same fields) and update the
modified field:
db.students2.updateMany( {}, [ { $replaceRoot: { newRoot: { $mergeObjects: [ { quiz1: 0, quiz2: 0, test1: 0, test2: 0 }, "$$ROOT" ] } } }, { $set: { modified: "$$NOW"} } ] )
Specifically, the pipeline consists of:
a
$replaceRootstage with a$mergeObjectsexpression to set default values for thequiz1,quiz2,test1andtest2fields. The aggregation variableROOTrefers to the current document being modified. To access the variable, prefix with$$and enclose in quotes. The current document fields will override the default values.a
$setstage to update themodifiedfield to the current datetime. The operation uses the aggregation variableNOWfor the current datetime. To access the variable, prefix with$$and enclose in quotes.
To verify the update, you can query the collection:
db.students2.find()
updateMany with $set
Create an example students3 collection (if the collection does not
currently exist, insert operations will create the collection):
db.students3.insert([ { "_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 verify, query the collection:
db.students3.find()
The following db.collection.updateMany() operation uses an
aggregation pipeline to update the documents with the calculated
grade average and letter grade.
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" } } } } ] )
Specifically, the pipeline consists of:
a
$setstage to calculate the truncated average value of thetestsarray elements and to update themodifiedfield to the current datetime. To calculate the truncated average, the stage uses the$avgand$truncexpressions. The operation uses the aggregation variableNOWfor the current datetime. To access the variable, prefix with$$and enclose in quotes.a
$setstage to add thegradefield based on theaverageusing the$switchexpression.
To verify the update, you can query the collection:
db.students3.find()
updateOne with $set
Create an example students4 collection (if the collection does
not currently exist, insert operations will create the collection):
db.students4.insertMany([ { "_id" : 1, "quizzes" : [ 4, 6, 7 ] }, { "_id" : 2, "quizzes" : [ 5 ] }, { "_id" : 3, "quizzes" : [ 10, 10, 10 ] } ])
To verify, query the collection:
db.students4.find()
The following db.collection.updateOne() operation uses an
aggregation pipeline to add quiz scores to the document with _id:
2:
db.students4.updateOne( { _id: 2 }, [ { $set: { quizzes: { $concatArrays: [ "$quizzes", [ 8, 6 ] ] } } } ] )
To verify the update, query the collection:
db.students4.find()
updateMany with $addFields
Create an example temperatures collection that contains
temperatures in Celsius (if the collection does not currently exist,
insert operations will create the collection):
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 verify, query the collection:
db.temperatures.find()
The following db.collection.updateMany() operation uses an
aggregation pipeline to update the documents with the corresponding
temperatures in Fahrenheit:
db.temperatures.updateMany( { }, [ { $addFields: { "tempsF": { $map: { input: "$tempsC", as: "celsius", in: { $add: [ { $multiply: ["$$celsius", 9/5 ] }, 32 ] } } } } } ] )
Specifically, the pipeline consists of an $addFields
stage to add a new array field tempsF that contains the
temperatures in Fahrenheit. To convert each celsius temperature in
the tempsC array to Fahrenheit, the stage uses the
$map expression with $add and
$multiply expressions.
To verify the update, you can query the collection:
db.temperatures.find()
Additional Examples
See also the various update method pages for additional examples: