findAndModify

Definition

  • findAndModify
  • The findAndModify command modifies and returns a singledocument. By default, the returned document does not include themodifications made on the update. To return the document with themodifications made on the update, use the new option.

The command has the following syntax:

  1. {
  2. findAndModify: <collection-name>,
  3. query: <document>,
  4. sort: <document>,
  5. remove: <boolean>,
  6. update: <document or aggregation pipeline>, // Changed in MongoDB 4.2
  7. new: <boolean>,
  8. fields: <document>,
  9. upsert: <boolean>,
  10. bypassDocumentValidation: <boolean>,
  11. writeConcern: <document>,
  12. collation: <document>,
  13. arrayFilters: <array>
  14. }

The findAndModify command takes the followingfields:

FieldTypeDescriptionquerydocumentOptional. 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, findAndModifywill 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.sortdocumentOptional. Determines which document the operation modifies if the query selectsmultiple documents. 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.removebooleanMust specify either the remove or the update field. Removesthe document specified in the query field. Set this to trueto remove the selected document . The default is false.updatedocument or arrayMust specify either the remove or the update field. Performsan update of the selected document.

  • If passed a document with update operator expressions, findAndModify performs the specifiedmodification.
  • If passed a replacement document { <field1>: <value1>, …},the findAndModify performs a replacement.
  • Starting in MongoDB 4.2, if passed an aggregation pipeline [ <stage1>, <stage2>, … ],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.newbooleanOptional. When true, returns the modified document rather than the original.The findAndModify method ignores thenew option for remove operations. The default is false.fieldsdocumentOptional. A subset of fields to return. The fields document specifies aninclusion of a field with 1, 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.upsertbooleanOptional. 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 the query fieldsare uniquely indexed.

Defaults to false.bypassDocumentValidationbooleanOptional. Enables findAndModify to bypass document validationduring the operation. This lets you update documents that do notmeet the validation requirements.

New in version 3.2.

writeConcerndocumentOptional. 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.

maxTimeMSintegerOptional. Specifies a time limit in milliseconds for processing the operation.findAndModifystringThe collection against which to run the command.collationdocumentOptional.

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:

  1. collation: {
  2. locale: <string>,
  3. caseLevel: <boolean>,
  4. caseFirst: <string>,
  5. strength: <int>,
  6. numericOrdering: <boolean>,
  7. alternate: <string>,
  8. maxVariable: <string>,
  9. backwards: <boolean>
  10. }

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.

arrayFiltersarrayOptional. 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:

  1. // INVALID
  2.  
  3. [
  4. { "x.a": { $gt: 85 } },
  5. { "x.b": { $gt: 80 } }
  6. ]

However, you can specify compound conditions on the same identifierin a single filter document, such as in the following examples:

  1. // Example 1
  2. [
  3. { $or: [{"x.a": {$gt: 85}}, {"x.b": {$gt: 80}}] }
  4. ]
  5. // Example 2
  6. [
  7. { $and: [{"x.a": {$gt: 85}}, {"x.b": {$gt: 80}}] }
  8. ]
  9. // Example 3
  10. [
  11. { "x.a": { $gt: 85 }, "x.b": { $gt: 80 } }
  12. ]

For examples, see Array Update Operations with arrayFilters.

Note

arrayFilters is not available for updates that use anaggregation pipeline.

New in version 3.6.

Output

The findAndModify command returns a document with thefollowing fields:

FieldTypeDescription
valuedocumentContains the command’s returned value. See valuefor details.
lastErrorObjectdocumentContains information about updated documents. SeelastErrorObject for details.
oknumberContains the command’s execution status. 1 on success, or 0 if anerror occurred.

lastErrorObject

The lastErrorObject embedded document contains the following fields:

FieldTypeDescription
updatedExistingbooleanContains true if an update operation modified an existing document.
upserteddocumentContains the ObjectId of the inserted document if an updateoperation with upsert: true resulted in a new document.

value

For remove operations, value contains the removed document ifthe query matches a document. If the query does not match a document toremove, value contains null.

For update operations, the value embedded document contains thefollowing:

  • If the new parameter is not set or is false:
    • the pre-modification document if the query matches a document;
    • otherwise, null.
  • If new is true:
    • 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, findAndModify returns an empty document {} in the value field instead of null.

Behavior

Upsert and Unique Index

When the findAndModify command includes the upsert:true option and the query field(s) is not uniquely indexed, thecommand could insert a document multiple times in certain circumstances.

Consider an example where no document with the name Andy exists andmultiple clients issue the following command:

  1. db.runCommand(
  2. {
  3. findAndModify: "people",
  4. query: { name: "Andy" },
  5. sort: { rating: 1 },
  6. update: { $inc: { score: 1 } },
  7. upsert: true
  8. }
  9. )

If all the commands finish the query phase before any commandstarts the modify phase, and there is no unique index on thename field, the commands may each perform an upsert, creatingmultiple duplicate documents.

To prevent the creation of multiple duplicate documents,create a unique index onthe name field. With the unique index in place, then the multiplefindAndModify commands will exhibit one of thefollowing behaviors:

  • Exactly one findAndModify successfully inserts anew document.
  • Zero or more findAndModify commands update thenewly inserted document.
  • Zero or more findAndModify commands fail whenthey attempt to insert a duplicate. If the command fails due toa unique index constraint violation, you can retry the command.Absent a delete of the document, the retry should not fail.

Sharded Collections

To use findAndModify on a sharded collection, the queryfilter must include an equality condition on the shard key.

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 findAndModify command 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, findAndModify and theupdate() method operate differently:

  • By default, both operations modify a single document. However, theupdate() method with its multi optioncan modify more than one document.

  • If multiple documents match the update criteria, forfindAndModify, you can specify a sort 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, findAndModify returns an object that contains the pre-modified version of thedocument, as well as the status of the operation. Toobtain the updated document, use the new 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 findAndModify and theupdate() method atomically update thedocument. See Atomicity and Transactions for moredetails about interactions and order of operations of these methods.

Transactions

findAndModify can be used inside multi-document transactions.

If the operation results in an upsert, the collection must already exist.

Do not explicitly set the write concern for the operation if run ina transaction. To use write concern with transactions, seeTransactions and Write Concern.

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.

Examples

Update and Return

The following command updates an existing document in the peoplecollection where the document matches the query criteria:

  1. db.runCommand(
  2. {
  3. findAndModify: "people",
  4. query: { name: "Tom", state: "active", rating: { $gt: 10 } },
  5. sort: { rating: 1 },
  6. update: { $inc: { score: 1 } }
  7. }
  8. )

This command performs the following actions:

  • The query finds a document in the people collection where thename field has the value Tom, the state field hasthe value active and the rating field has a valuegreater than 10.

  • The sort orders the results of the query in ascending order.If multiple documents meet the query condition, the command willselect for modification the first document as ordered by thissort.

  • The update increments the value of thescore field by 1.

  • The command returns a document with the following fields:

    • The lastErrorObject field that contains the details of thecommand, including the field updatedExisting which istrue, and

    • The value field that contains the original (i.e.pre-modification) document selected for this update:

  1. {
  2. "lastErrorObject" : {
  3. "connectionId" : 1,
  4. "updatedExisting" : true,
  5. "n" : 1,
  6. "syncMillis" : 0,
  7. "writtenTo" : null,
  8. "err" : null,
  9. "ok" : 1
  10. },
  11. value" : {
  12. "_id" : ObjectId("54f62d2885e4be1f982b9c9c"),
  13. "name" : "Tom",
  14. "state" : "active",
  15. "rating" : 100,
  16. "score" : 5
  17. },
  18. "ok" : 1
  19. }

To return the modified document in the value field, add thenew:true option to the command.

If no document match the query condition, the commandreturns a document that contains null in the valuefield:

  1. { "value" : null, "ok" : 1 }

The mongo shell and many driversprovide a findAndModify() helper method.Using the shell helper, this previous operation can take thefollowing form:

  1. db.people.findAndModify( {
  2. query: { name: "Tom", state: "active", rating: { $gt: 10 } },
  3. sort: { rating: 1 },
  4. update: { $inc: { score: 1 } }
  5. } );

However, the findAndModify() shell helpermethod returns only the unmodified document, or if new istrue, the modified document.

  1. {
  2. "_id" : ObjectId("54f62d2885e4be1f982b9c9c"),
  3. "name" : "Tom",
  4. "state" : "active",
  5. "rating" : 100,
  6. "score" : 5
  7. }

upsert: true

The following findAndModify command includes the upsert:true option for the update operation to either update a matchingdocument or, if no matching document exists, create a new document:

  1. db.runCommand(
  2. {
  3. findAndModify: "people",
  4. query: { name: "Gus", state: "active", rating: 100 },
  5. sort: { rating: 1 },
  6. update: { $inc: { score: 1 } },
  7. upsert: true
  8. }
  9. )

If the command finds a matching document, the command performs an update.

If the command does not find a matching document, the updatewith upsert: true operation results in an insertionand returns a document with the following fields:

  • The lastErrorObject field that contains the details of thecommand, including the field upserted that contains the_id value of the newly inserted document, and
  • The value field containing null.
  1. {
  2. "value" : null,
  3. "lastErrorObject" : {
  4. "updatedExisting" : false,
  5. "n" : 1,
  6. "upserted" : ObjectId("54f62c8bc85d4472eadea26f")
  7. },
  8. "ok" : 1
  9. }

Return New Document

The following findAndModify command includes bothupsert: true option and the new:true option. The command eitherupdates a matching document and returns the updated document or, if nomatching document exists, inserts a document and returns the newlyinserted document in the value field.

In the following example, no document in the people collectionmatches the query condition:

  1. db.runCommand(
  2. {
  3. findAndModify: "people",
  4. query: { name: "Pascal", state: "active", rating: 25 },
  5. sort: { rating: 1 },
  6. update: { $inc: { score: 1 } },
  7. upsert: true,
  8. new: true
  9. }
  10. )

The command returns the newly inserted document in the value field:

  1. {
  2. "lastErrorObject" : {
  3. "connectionId" : 1,
  4. "updatedExisting" : false,
  5. "upserted" : ObjectId("54f62bbfc85d4472eadea26d"),
  6. "n" : 1,
  7. "syncMillis" : 0,
  8. "writtenTo" : null,
  9. "err" : null,
  10. "ok" : 1
  11. },
  12. "value" : {
  13. "_id" : ObjectId("54f62bbfc85d4472eadea26d"),
  14. "name" : "Pascal",
  15. "rating" : 25,
  16. "state" : "active",
  17. "score" : 1
  18. },
  19. "ok" : 1
  20. }

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:

  1. db.runCommand(
  2. {
  3. findAndModify: "people",
  4. query: { state: "active" },
  5. sort: { rating: 1 },
  6. remove: true
  7. }
  8. )

The command returns the deleted document:

  1. {
  2. "lastErrorObject" : {
  3. "connectionId" : 1,
  4. "n" : 1,
  5. "syncMillis" : 0,
  6. "writtenTo" : null,
  7. "err" : null,
  8. "ok" : 1
  9. },
  10. "value" : {
  11. "_id" : ObjectId("54f62a6785e4be1f982b9c9b"),
  12. "name" : "XYZ123",
  13. "score" : 1,
  14. "state" : "active",
  15. "rating" : 3
  16. },
  17. "ok" : 1
  18. }

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:

  1. { _id: 1, category: "café", status: "A" }
  2. { _id: 2, category: "cafe", status: "a" }
  3. { _id: 3, category: "cafE", status: "a" }

The following operation includes the collationoption:

  1. db.runCommand(
  2. {
  3. findAndModify: "myColl",
  4. query: { category: "cafe", status: "a" },
  5. sort: { category: 1 },
  6. update: { $set: { status: "Updated" } },
  7. collation: { locale: "fr", strength: 1 }
  8. }
  9. )

The operation returns the following document:

  1. {
  2. "lastErrorObject" : {
  3. "updatedExisting" : true,
  4. "n" : 1
  5. },
  6. "value" : {
  7. "_id" : 1,
  8. "category" : "café",
  9. "status" : "A"
  10. },
  11. "ok" : 1
  12. }

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:

  1. db.students.insert([
  2. { "_id" : 1, "grades" : [ 95, 92, 90 ] },
  3. { "_id" : 2, "grades" : [ 98, 100, 102 ] },
  4. { "_id" : 3, "grades" : [ 95, 110, 100 ] }
  5. ])

To modify all elements that are greater than or equal to 100 in thegrades array, use the positional $[<identifier>]operator with the arrayFilters option:

  1. db.runCommand(
  2. {
  3. findAndModify: "students",
  4. query: { grades: { $gte: 100 } },
  5. update: { $set: { "grades.$[element]" : 100 } },
  6. arrayFilters: [ { "element": { $gte: 100 } } ]
  7. }
  8. )

The operation updates the grades field for a single document, andafter the operation, the collection has the following documents:

  1. { "_id" : 1, "grades" : [ 95, 92, 90 ] }
  2. { "_id" : 2, "grades" : [ 98, 100, 100 ] }
  3. { "_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:

  1. db.students2.insert([
  2. {
  3. "_id" : 1,
  4. "grades" : [
  5. { "grade" : 80, "mean" : 75, "std" : 6 },
  6. { "grade" : 85, "mean" : 90, "std" : 4 },
  7. { "grade" : 85, "mean" : 85, "std" : 6 }
  8. ]
  9. },
  10. {
  11. "_id" : 2,
  12. "grades" : [
  13. { "grade" : 90, "mean" : 75, "std" : 6 },
  14. { "grade" : 87, "mean" : 90, "std" : 3 },
  15. { "grade" : 85, "mean" : 85, "std" : 4 }
  16. ]
  17. }
  18. ])

The following operation finds a document where the id field equals1 and uses the filtered positional operator [$[<identifier>]]($ec4d226916b8aa6c.md#up._S[]) withthe arrayFilters to modify the mean for all elements in thegrades array where the grade is greater than or equal to 85.

  1. db.runCommand(
  2. {
  3. findAndModify: "students2",
  4. query: { _id : 1 },
  5. update: { $set: { "grades.$[elem].mean" : 100 } },
  6. arrayFilters: [ { "elem.grade": { $gte: 85 } } ]
  7. }
  8. )

The operation updates the grades field for a single document, and after theoperation, the collection has the following documents:

  1. {
  2. "_id" : 1,
  3. "grades" : [
  4. { "grade" : 80, "mean" : 75, "std" : 6 },
  5. { "grade" : 85, "mean" : 100, "std" : 4 },
  6. { "grade" : 85, "mean" : 100, "std" : 6 }
  7. ]
  8. }
  9. {
  10. "_id" : 2,
  11. "grades" : [
  12. { "grade" : 90, "mean" : 75, "std" : 6 },
  13. { "grade" : 87, "mean" : 90, "std" : 3 },
  14. { "grade" : 85, "mean" : 85, "std" : 4 }
  15. ]
  16. }

Use an Aggregation Pipeline for Updates

Starting in MongoDB 4.2, findAndModify can accept anaggregation pipeline for the update. The pipeline can consist of thefollowing stages:

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:

  1. db.students2.insert([
  2. {
  3. "_id" : 1,
  4. "grades" : [
  5. { "grade" : 80, "mean" : 75, "std" : 6 },
  6. { "grade" : 85, "mean" : 90, "std" : 4 },
  7. { "grade" : 85, "mean" : 85, "std" : 6 }
  8. ]
  9. },
  10. {
  11. "_id" : 2,
  12. "grades" : [
  13. { "grade" : 90, "mean" : 75, "std" : 6 },
  14. { "grade" : 87, "mean" : 90, "std" : 3 },
  15. { "grade" : 85, "mean" : 85, "std" : 4 }
  16. ]
  17. }
  18. ])

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:

  1. db.runCommand(
  2. {
  3. findAndModify: "students2",
  4. query: { "_id" : 1 },
  5. update: [ { $set: { "total" : { $sum: "$grades.grade" } } } ],
  6. new: true
  7. }
  8. )

Note

The $set used in the pipeline refers to the aggregation stage$set and not the update operator $set.

After the operation, the collection has the following documents:

  1. {
  2. "_id" : 1,
  3. "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 90, "std" : 4 }, { "grade" : 85, "mean" :85, "std" : 6 } ],
  4. "total" : 250
  5. }
  6. {
  7. "_id" : 2,
  8. "grades" : [ { "grade" : 90, "mean" : 75, "std" : 6 }, { "grade" : 87, "mean" : 90, "std" : 3 }, { "grade" : 85, "mean" : 85,"std" : 4 } ]
  9. }

See also

Linearizable Reads via findAndModify