In MongoDB, two popular methods for updating documents are findOneAndUpdate() and findAndModify(). In this article, we will explain both methods, demonstrate them on different datasets, find the differences and discover which one is best suited for your needs.
MongoDB findOneAndUpdate() Method
MongoDB findOneAndUpdate() method updates the first document that matches the given condition. Even if multiple documents satisfy the filter condition, only the first single document is selected for the update operation.
Syntax:
db.collection.findOneAndUpdate(
filter,
update,
options
)
Parameters:
- filter: Query or condition to find a document.
- update: Update operation to apply.
- options: Optional parameters like returnDocument, projection, sort.
For more details: MongoDB db.collection.findOneAndUpdate()
MongoDB findAndModify() Method
The findAndModify() also updates the first document that matches the given condition.
This method is older than findOneAndUpdate() and was used for a find-and-modify operation in MongoDB. It has been deprecated in favour of findOneAndUpdate() in the MongoDB shell but is still available in the Node.js driver for backward compatibility.
Syntax:
db.collection.findAndModify(
{
query: filter,
update: update,
sort: sort,
remove: remove,
new: new
}
)
Parameters:
- filter: Query or condition to find a document.
- update: Update operation to apply.
- sort: For performing any additional sorting.
- remove: Remove the selected document instead of updating it.
- new: Returns the updated document instead of the original one.
Also Read: Update Multiple Documents in MongoDB using updateMany()
Examples of findOneAndUpdate() and findAndModify() Methods
In this section, we will look at some examples of how we can use both findOneAndUpdate() and findAndModify() methods inside the Mongo shell.
Let’s first use the find() method to get all the documents that we will use for our examples:
{
"_id" : ObjectId("602eb6c728ff814b64eb3411"),
"name" : "Stephanie",
"age" : 22,
"breed" : "Persian Cat",
"personality" : {
"dogFriendly" : true,
"childFriendly" : true
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "30th May, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
{
"_id" : ObjectId("602eb73728ff814b64eb3412"),
"name" : "Whiskers",
"age" : 4,
"breed" : "Scottish Fold",
"personality" : {
"dogFriendly" : false,
"childFriendly" : true
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "5th Mar, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
{
"_id" : ObjectId("602eb84628ff814b64eb3413"),
"name" : "Krissy",
"age" : 6,
"breed" : "Turkish Angora",
"personality" : {
"dogFriendly" : true,
"childFriendly" : false
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "12th Dec, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
{
"_id" : ObjectId("602ebc5ea78db75e09057cd0"),
"name" : "Cassy",
"age" : 16,
"breed" : "Japanese Angora",
"personality" : {
"dogFriendly" : true,
"childFriendly" : false
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "26th Jul, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
{
"_id" : ObjectId("602ebc9da78db75e09057cd1"),
"name" : "Shane",
"age" : 11,
"breed" : "Bobtail",
"personality" : {
"dogFriendly" : false,
"childFriendly" : false
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "16th Sep, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
{
"_id" : ObjectId("602ebed7a78db75e09057cd2"),
"name" : "Phoebe",
"age" : 21,
"breed" : "Bobtail",
"personality" : {
"dogFriendly" : false,
"childFriendly" : false
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "20th Jan, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
Example 1: Operating on String Value Fields
In this example, we will use both methods on string fields.
Using findOneAndUpdate() Method:
Let’s say Stephanie got adopted and her owner has changed her name to Renee:
> db.cats.findOneAndUpdate({"name": "Stephanie"}, { $set: {"name": "Renee" }})
{
"_id" : ObjectId("602eb6c728ff814b64eb3411"),
"name" : "Stephanie",
"age" : 22,
"breed" : "Persian Cat",
"personality" : {
"dogFriendly" : true,
"childFriendly" : true
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "30th May, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
By default findoneandupdate returns the document in its unchanged form, which we got.
Let us see if a cat named Renee exists:
> db.cats.findOne({"name": "Renee"})
{
"_id" : ObjectId("602eb6c728ff814b64eb3411"),
"name" : "Renee",
"age" : 22,
"breed" : "Persian Cat",
"personality" : {
"dogFriendly" : true,
"childFriendly" : true
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "30th May, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
And it does!
Using findAndModify() Method:
Let’s say we mistakenly set the breed of some cats as Bobtail instead of Exotic Shorthair:
> db.cats.findAndModify(
... {
... query: { breed: "Bobtail" },
... update: { $set: { breed: "Exotic Shorthair" } }
... }
... )
{
"_id" : ObjectId("602ebc9da78db75e09057cd1"),
"name" : "Shane",
"age" : 11,
"breed" : "Bobtail",
"personality" : {
"dogFriendly" : false,
"childFriendly" : false
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "16th Sep, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
The findAndModify also returns the first document that matches the condition in its unchanged form.
To return with updated values, pass the new option as true:
> db.cats.findAndModify(
... {
... query: { breed: "Bobtail" },
... update: { $set: { breed: "American Shorthair" } },
... new: true
... }
... )
{
"_id" : ObjectId("602ebed7a78db75e09057cd2"),
"name" : "Phoebe",
"age" : 21,
"breed" : "American Shorthair",
"personality" : {
"dogFriendly" : false,
"childFriendly" : false
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "20th Jan, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
Now the returned document contains the updated value.
Example 2: Operating on Embedded Documents
In this example, we will use both methods and operate on an embedded document.
Using findOneAndUpdate() Method:
Let’s say Whiskers has got along well with dogs now and we no longer want to denounce him for not being a dog-friendly kitty.
We can use dot notation to access this embedded document field and update it to true:
> db.cats.findOneAndUpdate({name: "Whiskers"}, { $set: {"personality.dogFriendly": true }})
{
"_id" : ObjectId("602eb73728ff814b64eb3412"),
"name" : "Whiskers",
"age" : 4,
"breed" : "Scottish Fold",
"personality" : {
"dogFriendly" : false,
"childFriendly" : true
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "5th Mar, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
Let’s take a look at the updated document:
> db.cats.findOne({"name": "Whiskers"})
{
"_id" : ObjectId("602eb73728ff814b64eb3412"),
"name" : "Whiskers",
"age" : 4,
"breed" : "Scottish Fold",
"personality" : {
"dogFriendly" : true,
"childFriendly" : true
},
"moreDetails" : {
"cost" : 30000,
"adoptionDate" : "5th Mar, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
Perfect! We now have the dogFriendly field as true.
Using findAndModify() Method:
Let’s change the cost of Krissy to 23000 using the dot notation:
> db.cats.findAndModify(
... {
... query: { name: "Krissy" },
... update: { $set: { "moreDetails.cost": 23000} },
... new: true
... }
... )
{
"_id" : ObjectId("602eb84628ff814b64eb3413"),
"name" : "Krissy",
"age" : 6,
"breed" : "Turkish Angora",
"personality" : {
"dogFriendly" : true,
"childFriendly" : false
},
"moreDetails" : {
"cost" : 23000,
"adoptionDate" : "12th Dec, 2021"
},
"likes" : [
"fish",
"milk",
"chicken",
"blankets"
]
}
Awesome! We now have the updated value returned with the cost set to 23000.
Conclusion
In short, we saw that both findOneAndUpdate() and findAndModify() methods are used to select documents based on some given condition and update the very first document accordingly.
If you are building a new application with MongoDB as a database that requires updating documents, we recommend using findOneAndUpdate(), it is modern and simpler to use, whereas findAndModify() is old, complex, and deprecated.
But if you have an older project using MongoDB, chances are high that it may be better compatible with findAndModify(). See if you can migrate to findOneAndUpdate() otherwise sticking to findAndModify() is not a big problem as is still supported in Node.js.
References
- https://docs.mongodb.com/v4.4/reference/method/db.collection.findAndModify
- https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate