db.collection.findOneAndUpdate()
Definition
mongo
Shell Method
This page documents the mongo
shell method, and doesnot refer to the MongoDB Node.js driver (or any other driver)method. For corresponding MongoDB driver API, refer to your specificMongoDB driver documentation instead.
New in version 3.2.
Updates a single document based on the filter
andsort
criteria.
The findOneAndUpdate()
method has the followingform:
- db.collection.findOneAndUpdate(
- <filter>,
- <update document or aggregation pipeline>, // Changed in MongoDB 4.2
- {
- projection: <document>,
- sort: <document>,
- maxTimeMS: <number>,
- upsert: <boolean>,
- returnNewDocument: <boolean>,
- collation: <document>,
- arrayFilters: [ <filterdocument1>, ... ]
- }
- )
The findOneAndUpdate()
method takes the followingparameters:
ParameterTypeDescriptionfilter
documentThe selection criteria for the update. The same queryselectors as in the find()
method are available.
Specify an empty document { }
to update the first document returned inthe collection.
If unspecified, defaults to an empty document.
Starting in MongoDB 4.2 (and 4.0.12+, 3.6.14+, and 3.4.23+), the operationerrors if the query argument is not a document.update
document or arrayThe update document or, starting in MongoDB 4.2, an aggregationpipeline.
- If passed a document with update operator expressions,
db.collection.findOneAndUpdate()
performs the specifiedmodification.
Note
The document must contain only update operator expressions. You cannot specify a replacementdocument { <field1>: <value1>, …}
. To use a replacementdocument, see db.collection.findOneAndReplace()
instead.
Starting in MongoDB 4.2, if passed an aggregation pipeline
[ <stage1>, <stage2>, … ]
,db.collection.findOneAndUpdate()
modifies the document per the pipeline. The pipelinecan consist of the following stages:$addFields
and its alias$set
$project
and its alias$unset
$replaceRoot
and its alias$replaceWith
.projection
documentOptional. A subset of fields to return.
To return all fields in the returned document, omit this parameter.
Starting in MongoDB 4.2 (and 4.0.12+, 3.6.14+, and 3.4.23+), the operationerrors if the projection argument is not a document.sort
documentOptional. Specifies a sorting order for the documents matched by the filter
.
Starting in MongoDB 4.2 (and 4.0.12+, 3.6.14+, and 3.4.23+), the operationerrors if the sort argument is not a document.
See cursor.sort()
.maxTimeMS
numberOptional. Specifies a time limit in milliseconds within which the operation mustcomplete within. Throws an error if the limit is exceeded.upsert
booleanOptional. When true
, findOneAndUpdate()
either:
- Creates a new document if no documents match the
filter
.For more details see upsert behavior. Returnsnull
after inserting the new document, unlessreturnNewDocument
istrue
. - Updates a single document that matches the
filter
.To avoid multiple upserts, ensure that thefilter
fieldsare uniquely indexed.
Defaults to false
.returnNewDocument
booleanOptional. When true
, returns the updated document instead of the originaldocument.
Defaults to false
.collation
documentOptional.
Specifies the collation to use for the operation.
Collation allows users to specifylanguage-specific rules for string comparison, such as rules forlettercase and accent marks.
The collation option has the following syntax:
- collation: {
- locale: <string>,
- caseLevel: <boolean>,
- caseFirst: <string>,
- strength: <int>,
- numericOrdering: <boolean>,
- alternate: <string>,
- maxVariable: <string>,
- backwards: <boolean>
- }
When specifying collation, the locale
field is mandatory; allother collation fields are optional. For descriptions of the fields,see Collation Document.
If the collation is unspecified but the collection has adefault collation (see db.createCollection()
), theoperation uses the collation specified for the collection.
If no collation is specified for the collection or for theoperations, MongoDB uses the simple binary comparison used in priorversions for string comparisons.
You cannot specify multiple collations for an operation. Forexample, you cannot specify different collations per field, or ifperforming a find with a sort, you cannot use one collation for thefind and another for the sort.
New in version 3.4.
arrayFilters
arrayOptional. An array of filter documents that determine which array elements tomodify for an update operation on an array field.
In the update document, use the $[<identifier>]
filteredpositional operator to define an identifier, which you then referencein the array filter documents. You cannot have an array filterdocument for an identifier if the identifier is not included in theupdate document.
Note
The <identifier>
must begin with a lowercase letter andcontain only alphanumeric characters.
You can include the same identifier multiple times in the updatedocument; however, for each distinct identifier ($[identifier]
)in the update document, you must specify exactly onecorresponding array filter document. That is, you cannot specifymultiple array filter documents for the same identifier. Forexample, if the update statement includes the identifier x
(possibly multiple times), you cannot specify the following forarrayFilters
that includes 2 separate filter documents for x
:
- // INVALID
- [
- { "x.a": { $gt: 85 } },
- { "x.b": { $gt: 80 } }
- ]
However, you can specify compound conditions on the same identifierin a single filter document, such as in the following examples:
- // Example 1
- [
- { $or: [{"x.a": {$gt: 85}}, {"x.b": {$gt: 80}}] }
- ]
- // Example 2
- [
- { $and: [{"x.a": {$gt: 85}}, {"x.b": {$gt: 80}}] }
- ]
- // Example 3
- [
- { "x.a": { $gt: 85 }, "x.b": { $gt: 80 } }
- ]
For examples, see Array Update Operations with arrayFilters.
Note
arrayFilters
is not available for updates that use anaggregation pipeline.
New in version 3.6.
Returns:Returns either the original document or, if returnNewDocument: true
,the updated document.
Behavior
Document Match
db.collection.findOneAndUpdate()
updates the first matchingdocument in the collection that matches the filter
.The sort
parameter can be used to influence which document is updated.
Projection
The projection
parameter takes a document in the following form:
- { field1 : < boolean >, field2 : < boolean> ... }
The <boolean>
value can be any of the following:
1
ortrue
to include the field. The method returns the_id
field even if it is not explicitly stated in the projectionparameter.0
orfalse
to exclude the field. This can be used on anyfield, including_id
.
Sharded Collections
To use db.collection.findOneAndUpdate()
on a sharded collection, the query filter mustinclude an equality condition on the shard key.
Shard Key Modification
Starting in MongoDB 4.2, you can update a document’s shard key valueunless the shard key field is the immutable _id
field. For detailson updating the shard key, see Change a Document’s Shard Key Value.
Before MongoDB 4.2, a document’s shard key field value is immutable.
To use db.collection.findOneAndUpdate()
to update the shard key:
- You must run on a
mongos
either in atransaction or as a retryablewrite. Do not issue the operationdirectly on the shard. - You must include an equality condition on the full shardkey in the query filter. For example, if a collection
messages
uses{ country : 1, userid : 1 }
as the shard key, to updatethe shard key for a document, you must includecountry: <value>,userid: <value>
in the query filter. You can include additionalfields in the query as appropriate.
Transactions
db.collection.findOneAndUpdate()
can be used inside multi-document transactions.
Important
In most cases, multi-document transaction incurs a greaterperformance cost over single document writes, and theavailability of multi-document transactions should not be areplacement for effective schema design. For many scenarios, thedenormalized data model (embedded documents and arrays) will continue to be optimal for yourdata and use cases. That is, for many scenarios, modeling your dataappropriately will minimize the need for multi-documenttransactions.
For additional transactions usage considerations(such as runtime limit and oplog size limit), see alsoProduction Considerations.
Existing Collections and Transactions
Inside a transaction, you can specify read/write operations on existingcollections. If the db.collection.findOneAndUpdate()
results in anupsert, the collection must already exist.
If the operation results in an upsert, the collection must already exist.
Write Concerns and Transactions
Do not explicitly set the write concern for the operation if run ina transaction. To use write concern with transactions, seeTransactions and Write Concern.
Examples
Update A Document
The grades
collection contains documents similar to the following:
- { _id: 6305, name : "A. MacDyver", "assignment" : 5, "points" : 24 },
- { _id: 6308, name : "B. Batlock", "assignment" : 3, "points" : 22 },
- { _id: 6312, name : "M. Tagnum", "assignment" : 5, "points" : 30 },
- { _id: 6319, name : "R. Stiles", "assignment" : 2, "points" : 12 },
- { _id: 6322, name : "A. MacDyver", "assignment" : 2, "points" : 14 },
- { _id: 6234, name : "R. Stiles", "assignment" : 1, "points" : 10 }
The following operation finds the first document where name : R. Stiles
and increments the score by 5
:
- db.grades.findOneAndUpdate(
- { "name" : "R. Stiles" },
- { $inc: { "points" : 5 } }
- )
The operation returns the original document before the update:
- { _id: 6319, name: "R. Stiles", "assignment" : 2, "points" : 12 }
If returnNewDocument
was true, the operation would return theupdated document instead.
Sort And Update A Document
The grades
collection contains documents similar to the following:
- { _id: 6305, name : "A. MacDyver", "assignment" : 5, "points" : 24 },
- { _id: 6308, name : "B. Batlock", "assignment" : 3, "points" : 22 },
- { _id: 6312, name : "M. Tagnum", "assignment" : 5, "points" : 30 },
- { _id: 6319, name : "R. Stiles", "assignment" : 2, "points" : 12 },
- { _id: 6322, name : "A. MacDyver", "assignment" : 2, "points" : 14 },
- { _id: 6234, name : "R. Stiles", "assignment" : 1, "points" : 10 }
The following operation updates a document where name : "A. MacDyver"
. Theoperation sorts the matching documents by points
ascending to update thematching document with the least points.
- db.grades.findOneAndUpdate(
- { "name" : "A. MacDyver" },
- { $inc : { "points" : 5 } },
- { sort : { "points" : 1 } }
- )
The operation returns the original document before the update:
- { _id: 6322, name: "A. MacDyver", "assignment" : 2, "points" : 14 }
Project the Returned Document
The following operation uses projection to only display the _id
,points
, and assignment
fields in the returned document:
- db.grades.findOneAndUpdate(
- { "name" : "A. MacDyver" },
- { $inc : { "points" : 5 } },
- { sort : { "points" : 1 }, projection: { "assignment" : 1, "points" : 1 } }
- )
The operation returns the original document with only thefields specified in the projection
document and the _id
field as it was notexplicitly suppressed (_id: 0
) in the projection document.
- { "_id" : 6322, "assignment" : 2, "points" : 14 }
Update Document with Time Limit
The following operation sets a 5ms time limit to complete the update:
- try {
- db.grades.findOneAndUpdate(
- { "name" : "A. MacDyver" },
- { $inc : { "points" : 5 } },
- { sort: { "points" : 1 }, maxTimeMS : 5 };
- );
- }
- catch(e){
- print(e);
- }
If the operation exceeds the time limit, it returns:
- Error: findAndModifyFailed failed: { "ok" : 0, "errmsg" : "operation exceeded time limit", "code" : 50 }
Update Document with Upsert
The following operation uses the upsert
field to insert the updatedocument if nothing matches the filter
:
- try {
- db.grades.findOneAndUpdate(
- { "name" : "A.B. Abracus" },
- { $set: { "name" : "A.B. Abracus", "assignment" : 5}, $inc : { "points" : 5 } },
- { sort: { "points" : 1 }, upsert:true, returnNewDocument : true }
- );
- }
- catch (e){
- print(e);
- }
The operation returns the following:
- {
- "_id" : ObjectId("5789249f1c49e39a8adc479a"),
- "name" : "A.B. Abracus",
- "assignment" : 5,
- "points" : 5
- }
If returnNewDocument
was false, the operation would return null
asthere is no original document to return.
Specify Collation
New in version 3.4.
Collation allows users to specifylanguage-specific rules for string comparison, such as rules forlettercase and accent marks.
A collection myColl
has the following documents:
- { _id: 1, category: "café", status: "A" }
- { _id: 2, category: "cafe", status: "a" }
- { _id: 3, category: "cafE", status: "a" }
The following operation includes the collationoption:
- db.myColl.findOneAndUpdate(
- { category: "cafe" },
- { $set: { status: "Updated" } },
- { collation: { locale: "fr", strength: 1 } }
- );
The operation returns the following document:
- { "_id" : 1, "category" : "café", "status" : "A" }
Array Update Operations with arrayFilters
Note
arrayFilters
is not available for updates that use anaggregation pipeline.
New in version 3.6.
Starting in MongoDB 3.6, when updating an array field, you canspecify arrayFilters
that determine which array elements toupdate.
Update Elements Match arrayFilters Criteria
Note
arrayFilters
is not available for updates that use anaggregation pipeline.
Create a collection students
with the following documents:
- db.students.insert([
- { "_id" : 1, "grades" : [ 95, 92, 90 ] },
- { "_id" : 2, "grades" : [ 98, 100, 102 ] },
- { "_id" : 3, "grades" : [ 95, 110, 100 ] }
- ])
To modify all elements that are greater than or equal to 100
in thegrades
array, use the filtered positional operator$[<identifier>]
with the arrayFilters
option in thedb.collection.findOneAndUpdate
method:
- db.students.findOneAndUpdate(
- { grades: { $gte: 100 } },
- { $set: { "grades.$[element]" : 100 } },
- { arrayFilters: [ { "element": { $gte: 100 } } ] }
- )
The operation updates the grades
field for a single document, andafter the operation, the collection has the following documents:
- { "_id" : 1, "grades" : [ 95, 92, 90 ] }
- { "_id" : 2, "grades" : [ 98, 100, 100 ] }
- { "_id" : 3, "grades" : [ 95, 110, 100 ] }
Update Specific Elements of an Array of Documents
Note
arrayFilters
is not available for updates that use anaggregation pipeline.
Create a collection students2
with the following documents:
- db.students2.insert([
- {
- "_id" : 1,
- "grades" : [
- { "grade" : 80, "mean" : 75, "std" : 6 },
- { "grade" : 85, "mean" : 90, "std" : 4 },
- { "grade" : 85, "mean" : 85, "std" : 6 }
- ]
- },
- {
- "_id" : 2,
- "grades" : [
- { "grade" : 90, "mean" : 75, "std" : 6 },
- { "grade" : 87, "mean" : 90, "std" : 3 },
- { "grade" : 85, "mean" : 85, "std" : 4 }
- ]
- }
- ])
The following operation finds a document where the id
field equals1
and uses the filtered positional operator [$[<identifier>]
]($ec4d226916b8aa6c.md#up._S[arrayFilters
to modify the mean
for all elements in thegrades
array where the grade is greater than or equal to 85
.
- db.students2.findOneAndUpdate(
- { _id : 1 },
- { $set: { "grades.$[elem].mean" : 100 } },
- { arrayFilters: [ { "elem.grade": { $gte: 85 } } ] }
- )
The operation updates the grades
field for a single document, and after theoperation, the collection has the following documents:
- {
- "_id" : 1,
- "grades" : [
- { "grade" : 80, "mean" : 75, "std" : 6 },
- { "grade" : 85, "mean" : 100, "std" : 4 },
- { "grade" : 85, "mean" : 100, "std" : 6 }
- ]
- }
- {
- "_id" : 2,
- "grades" : [
- { "grade" : 90, "mean" : 75, "std" : 6 },
- { "grade" : 87, "mean" : 90, "std" : 3 },
- { "grade" : 85, "mean" : 85, "std" : 4 }
- ]
- }
Use an Aggregation Pipeline for Updates
Starting in MongoDB 4.2, db.collection.findOneAndUpdate()
canaccept an aggregation pipeline for the update. The pipeline can consistof the following stages:
$addFields
and its alias$set
$project
and its alias$unset
$replaceRoot
and its alias$replaceWith
.
Using the aggregation pipeline allows for a more expressive updatestatement, such as expressing conditional updates based on currentfield values or updating one field using the value of another field(s).
For example, create a collection students2
with the followingdocuments:
- db.students2.insert([
- {
- "_id" : 1,
- "grades" : [
- { "grade" : 80, "mean" : 75, "std" : 6 },
- { "grade" : 85, "mean" : 90, "std" : 4 },
- { "grade" : 85, "mean" : 85, "std" : 6 }
- ]
- },
- {
- "_id" : 2,
- "grades" : [
- { "grade" : 90, "mean" : 75, "std" : 6 },
- { "grade" : 87, "mean" : 90, "std" : 3 },
- { "grade" : 85, "mean" : 85, "std" : 4 }
- ]
- }
- ])
The following operation finds a document where the _id
field equals1
and uses an aggregation pipeline to calculate a new fieldtotal
from the grades
field:
- db.students2.findOneAndUpdate(
- { _id : 1 },
- [ { $set: { "total" : { $sum: "$grades.grade" } } } ], // The $set stage is an alias for ``$addFields`` stage
- { returnNewDocument: true }
- )
Note
The $set
used in the pipeline refers to the aggregation stage$set
and not the update operator $set
.
The operation returns the updated document :
- {
- "_id" : 1,
- "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 90, "std" : 4 }, { "grade" : 85, "mean" :85, "std" : 6 } ],
- "total" : 250
- }