db.collection.findAndModify()
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.
Modifies and returns a single document. By default, the returneddocument does not include the modifications made on the update. Toreturn the document with the modifications made on the update, usethe new
option. The findAndModify()
method is a shell helper around the findAndModify
command.
The findAndModify()
method has the followingform:
- db.collection.findAndModify({
- query: <document>,
- sort: <document>,
- remove: <boolean>,
- update: <document or aggregation pipeline>, // Changed in MongoDB 4.2
- new: <boolean>,
- fields: <document>,
- upsert: <boolean>,
- bypassDocumentValidation: <boolean>,
- writeConcern: <document>,
- collation: <document>,
- arrayFilters: [ <filterdocument1>, ... ]
- });
The db.collection.findAndModify()
method takes a documentparameter with the following embedded document fields:
ParameterTypeDescriptionquery
documentOptional. The selection criteria for the modification. The query
fieldemploys the same query selectors as used inthe db.collection.find()
method. Although the query maymatch multiple documents, db.collection.findAndModify()
will only select one document to modify.
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.sort
documentOptional. Determines which document the operation modifies if the query selectsmultiple documents. db.collection.findAndModify()
modifiesthe first document in the sort order specified by this argument.
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.remove
booleanMust specify either the remove
or the update
field. Removesthe document specified in the query
field. Set this to true
to remove the selected document . The default is false
.update
document or arrayMust specify either the remove
or the update
field. Performsan update of the selected document.
- If passed a document with update operator expressions,
db.collection.findAndModify()
performs the specifiedmodification. - If passed a replacement document
{ <field1>: <value1>, …}
,thedb.collection.findAndModify()
performs a replacement. - Starting in MongoDB 4.2, if passed an aggregation pipeline
[ <stage1>, <stage2>, … ]
,db.collection.findAndModify()
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
.new
booleanOptional. Whentrue
, returns the modified document rather than the original.Thedb.collection.findAndModify()
method ignores thenew
option forremove
operations. The default isfalse
.fields
documentOptional. A subset of fields to return. Thefields
document specifies aninclusion of a field with1
, as in:fields: { <field1>: 1,<field2>: 1, … }
. See projection.
Starting in MongoDB 4.2 (and 4.0.12+, 3.6.14+, and 3.4.23+), the operationerrors if the fields argument is not a document.upsert
booleanOptional. Used in conjuction with the update
field.
When true
, findAndModify()
either:
- Creates a new document if no documents match the
query
.For more details see upsert behavior. - Updates a single document that matches the
query
.To avoid multiple upserts, ensure that thequery
fieldsare uniquely indexed.
Defaults to false
.bypassDocumentValidation
booleanOptional. Enables db.collection.findAndModify
to bypass document validationduring the operation. This lets you update documents that do notmeet the validation requirements.
New in version 3.2.
writeConcern
documentOptional. A document expressing the write concern.Omit to use the default write concern.
Do not explicitly set the write concern for the operation if run ina transaction. To use write concern with transactions, seeTransactions and Write Concern.
New in version 3.2.
maxTimeMS
integerOptional. Specifies a time limit in milliseconds for processing the operation.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 Specify arrayFilters for an Array Update Operations.
Note
arrayFilters
is not available for updates that use anaggregation pipeline.
New in version 3.6.
Return Data
For remove operations, if the query matches a document,findAndModify()
returns the removed document.If the query does not match a document to remove,findAndModify()
returns null
.
For update operations, findAndModify()
returnsone of the following:
- If the
new
parameter is not set or isfalse
:- the pre-modification document if the query matches a document;
- otherwise,
null
.
- If
new
istrue
:- the modified document if the query returns a match;
- the inserted document if
upsert: true
and no document matches the query; - otherwise,
null
.
Changed in version 3.0: In previous versions, if for the update, sort
is specified,and upsert: true
, and the new
option is not set or new:false
, db.collection.findAndModify()
returns an empty document {}
instead of null
.
Behavior
Upsert and Unique Index
When findAndModify()
includes the upsert:true
option and the query field(s) is not uniquely indexed, themethod could insert a document multiple times in certain circumstances.
In the following example, no document with the name Andy
exists,and multiple clients issue the following command:
- db.people.findAndModify({
- query: { name: "Andy" },
- sort: { rating: 1 },
- update: { $inc: { score: 1 } },
- upsert: true
- })
Then, if these clients’ findAndModify()
methods finish the query
phase before any command starts themodify
phase, and there is no unique index on the name
field, the commands may all perform an upsert, creatingmultiple duplicate documents.
To prevent the creation of multiple duplicate documents with the samename, create a unique index on the name
field. With this unique index in place, the multiple methods willexhibit one of the following behaviors:
- Exactly one
findAndModify()
successfully inserts a new document. - Zero or more
findAndModify()
methodsupdate the newly inserted document. - Zero or more
findAndModify()
methods failwhen they attempt to insert documents with the same name. If themethod fails due to the unique index constraint violation on thename
field, you can retry the method. Absent a delete of thedocument, the retry should not fail.
Sharded Collections
When using findAndModify
in a shardedenvironment, the query
must contain an equality condition onshard key for all operations against the sharded cluster forthe sharded collections.
findAndModify
operations issued against mongos
instances for non-sharded collections function normally.
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.
Document Validation
The db.collection.findAndModify()
method adds support for thebypassDocumentValidation
option, which lets you bypassdocument validation wheninserting or updating documents in a collection with validationrules.
Comparisons with the update Method
When updating a document, db.collection.findAndModify()
and theupdate()
method operate differently:
By default, both operations modify a single document. However, the
update()
method with itsmulti
optioncan modify more than one document.If multiple documents match the update criteria, for
db.collection.findAndModify()
, you can specify asort
to provide somemeasure of control on which document to update.
With the default behavior of the update()
method, you cannot specify which single document to update whenmultiple documents match.
- By default,
db.collection.findAndModify()
returns the pre-modified version of the document. Toobtain the updated document, use thenew
option.
The update()
method returns aWriteResult
object that contains the status of the operation.To return the updated document, use the find()
method. However, other updates may have modified the document betweenyour update and the document retrieval. Also, if the update modifiedonly a single document but multiple documents matched, you will need touse additional logic to identify the updated document.
When modifying a single document, both db.collection.findAndModify()
and theupdate()
method atomically update thedocument. See Atomicity and Transactions for moredetails about interactions and order of operations of these methods.
Transactions
db.collection.findAndModify()
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.findAndModify()
results in anupsert, 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 and Return
The following method updates and returns an existing document in thepeople collection where the document matches the query criteria:
- db.people.findAndModify({
- query: { name: "Tom", state: "active", rating: { $gt: 10 } },
- sort: { rating: 1 },
- update: { $inc: { score: 1 } }
- })
This method performs the following actions:
The
query
finds a document in thepeople
collectionwhere thename
field has the valueTom
, thestate
field has the valueactive
and therating
field has avaluegreater than
10.The
sort
orders the results of the query in ascending order.If multiple documents meet thequery
condition, the methodwill select for modification the first document as ordered bythissort
.The update
increments
the value of thescore
field by 1.The method returns the original (i.e. pre-modification) documentselected for this update:
- {
- "_id" : ObjectId("50f1e2c99beb36a0f45c6453"),
- "name" : "Tom",
- "state" : "active",
- "rating" : 100,
- "score" : 5
- }
To return the modified document, add the new:true
option tothe method.
If no document matched the query
condition, the methodreturns null
.
Upsert
The following method includes the upsert: true
option for theupdate
operation to either update a matching document or, if nomatching document exists, create a new document:
- db.people.findAndModify({
- query: { name: "Gus", state: "active", rating: 100 },
- sort: { rating: 1 },
- update: { $inc: { score: 1 } },
- upsert: true
- })
If the method finds a matching document, the method performs an update.
If the method does not find a matching document, the method createsa new document. Because the method included the sort
option, itreturns an empty document { }
as the original (pre-modification)document:
- { }
If the method did not include a sort
option, the method returnsnull
.
- null
Return New Document
The following method includes both the upsert: true
option and thenew:true
option. The method either updates a matching document andreturns the updated document or, if no matching document exists,inserts a document and returns the newly inserted document in thevalue
field.
In the following example, no document in the people
collectionmatches the query
condition:
- db.people.findAndModify({
- query: { name: "Pascal", state: "active", rating: 25 },
- sort: { rating: 1 },
- update: { $inc: { score: 1 } },
- upsert: true,
- new: true
- })
The method returns the newly inserted document:
- {
- "_id" : ObjectId("50f49ad6444c11ac2448a5d6"),
- "name" : "Pascal",
- "rating" : 25,
- "score" : 1,
- "state" : "active"
- }
Sort and Remove
By including a sort
specification on the rating
field, thefollowing example removes from the people
collection a singledocument with the state
value of active
and the lowestrating
among the matching documents:
- db.people.findAndModify(
- {
- query: { state: "active" },
- sort: { rating: 1 },
- remove: true
- }
- )
The method returns the deleted document:
- {
- "_id" : ObjectId("52fba867ab5fdca1299674ad"),
- "name" : "XYZ123",
- "score" : 1,
- "state" : "active",
- "rating" : 3
- }
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.findAndModify({
- query: { category: "cafe", status: "a" },
- sort: { category: 1 },
- update: { $set: { status: "Updated" } },
- collation: { locale: "fr", strength: 1 }
- });
The operation returns the following document:
- { "_id" : 1, "category" : "café", "status" : "A" }
Specify arrayFilters for an Array Update Operations
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.findAndModify
method:
- db.students.findAndModify({
- query: { grades: { $gte: 100 } },
- update: { $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.findAndModify({
- query: { _id : 1 },
- update: { $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.findAndModify()
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 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 an aggregation pipeline to calculate a new fieldtotal
from the grades
field:
- db.students2.findAndModify( {
- query: { "_id" : 1 },
- update: [ { $set: { "total" : { $sum: "$grades.grade" } } } ], // The $set stage is an alias for ``$addFields`` stage
- new: 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
- }
See also