Updates with Aggregation Pipeline
Starting in MongoDB 4.2, you can use the aggregation pipeline for update operations. 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).
Example 1
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()
Example 2
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
$replaceRoot
stage with a$mergeObjects
expression to set default values for thequiz1
,quiz2
,test1
andtest2
fields. The aggregation variableROOT
refers 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
$set
stage to update themodified
field to the current datetime. The operation uses the aggregation variableNOW
for 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()
Example 3
Create an example students3
collection (if the collection does not
currently exist, insert operations will create the collection):
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 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
$set
stage to calculate the truncated average value of thetests
array elements and to update themodified
field to the current datetime. To calculate the truncated average, the stage uses the$avg
and$trunc
expressions. The operation uses the aggregation variableNOW
for the current datetime. To access the variable, prefix with$$
and enclose in quotes.a
$set
stage to add thegrade
field based on theaverage
using the$switch
expression.
To verify the update, you can query the collection:
db.students3.find()
Example 4
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()
Example 5
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: