db.collection.findAndModify()

Definition

  • db.collection.findAndModify(document)

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

The findAndModify() method has the followingform:

  1. db.collection.findAndModify({
  2. query: <document>,
  3. sort: <document>,
  4. remove: <boolean>,
  5. update: <document or aggregation pipeline>, // Changed in MongoDB 4.2
  6. new: <boolean>,
  7. fields: <document>,
  8. upsert: <boolean>,
  9. bypassDocumentValidation: <boolean>,
  10. writeConcern: <document>,
  11. collation: <document>,
  12. arrayFilters: [ <filterdocument1>, ... ]
  13. });

The db.collection.findAndModify() method takes a documentparameter with the following embedded document fields:

ParameterTypeDescriptionquerydocumentOptional. 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.sortdocumentOptional. 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.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.

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

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

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

Then, if these clients’ findAndModify()methods finish the query phase before any command starts themodify phase, and there is no unique index on the namefield, 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 namefield. 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 mongosinstances 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, theupdate() method with its multi optioncan modify more than one document.

  • If multiple documents match the update criteria, fordb.collection.findAndModify(), 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.

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:

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

This method performs the following actions:

  • The query finds a document in the people collectionwhere the name field has the value Tom, the statefield has the value active and the rating field has avalue greater than 10.

  • The sort orders the results of the query in ascending order.If multiple documents meet the query condition, the methodwill select for modification the first document as ordered bythis sort.

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

  • The method returns the original (i.e. pre-modification) documentselected for this update:

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

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:

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

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:

  1. { }

If the method did not include a sort option, the method returnsnull.

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

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

The method returns the newly inserted document:

  1. {
  2. "_id" : ObjectId("50f49ad6444c11ac2448a5d6"),
  3. "name" : "Pascal",
  4. "rating" : 25,
  5. "score" : 1,
  6. "state" : "active"
  7. }

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.people.findAndModify(
  2. {
  3. query: { state: "active" },
  4. sort: { rating: 1 },
  5. remove: true
  6. }
  7. )

The method returns the deleted document:

  1. {
  2. "_id" : ObjectId("52fba867ab5fdca1299674ad"),
  3. "name" : "XYZ123",
  4. "score" : 1,
  5. "state" : "active",
  6. "rating" : 3
  7. }

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.myColl.findAndModify({
  2. query: { category: "cafe", status: "a" },
  3. sort: { category: 1 },
  4. update: { $set: { status: "Updated" } },
  5. collation: { locale: "fr", strength: 1 }
  6. });

The operation returns the following document:

  1. { "_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:

  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 filtered positional operator$[<identifier>] with the arrayFilters option in thedb.collection.findAndModify method:

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

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.students2.findAndModify({
  2. query: { _id : 1 },
  3. update: { $set: { "grades.$[elem].mean" : 100 } },
  4. arrayFilters: [ { "elem.grade": { $gte: 85 } } ]
  5. })

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, db.collection.findAndModify() canaccept an aggregation pipeline for the update. The pipeline can consistof the following 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 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 an aggregation pipeline to calculate a new fieldtotal from the grades field:

  1. db.students2.findAndModify( {
  2. query: { "_id" : 1 },
  3. update: [ { $set: { "total" : { $sum: "$grades.grade" } } } ], // The $set stage is an alias for ``$addFields`` stage
  4. new: true
  5. } )

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:

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

See also

Linearizable Reads via findAndModify