findOneAndUpdate() and findAndModify() in MongoDB

A MongoDB database has multiple collections. These collections can store millions of documents(data in MongoDB is called a document). MongoDB has various methods to fetch the documents from a collection such as find(), findOne(), findOneAndUpdate(), etc.

We already have covered the find() and findOne() methods, in this tutorial we will provide a comprehensive guide to using the methods findOneAndUpdate() and findAndModify() in MongoDB.

Both findOneAndUpdate() and findAndModify() functions perform a find and an update operation. This guide aims to provide readers with examples to illustrate the usage of the two.

Syntax for findOneAndUpdate() and findAndModify() Functions

Let us take a quick look at the syntaxes for both functions below:

Syntax of findOneAndUpdate() Function

db.collection.findOneAndUpdate( filter, update, options )

Syntax of findAndModify() Function

db.collection.findAndModify(document)

Using the findOneAndUpdate() and findAndModify() Functions

Let us now get started by looking at some examples for both the functions in MongoDB inside the mongo shell. Below is the collection that I will be using for today’s tutorial.

{
        "_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"
        ]
}

Operating on String Value Fields Using the findOneAndUpdate() and findAndModify() Functions

In this example, I will use both functions on string fields and demonstrate them as different examples.

Using findOneAndUpdate() Function

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"
        ]
}

You must have noticed that the findOneAndUpdate() function immediately returns the selected documents in their unchanged form.

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() Function

Let’s say we mistakenly set the breed of some cats as Bobtail instead of Exotic Shorthair. Remember, the findAndModify() function only updates the first document that matches the query.

> 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"
        ]
}

We have again received the unmodified version of the document. To return with updated values, pass the new option as true. Let us try it out and simultaneously check if the document is updated or not. We will do this for the other Bobtail we have – Phoebe.

> 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"
        ]
}

Great! We have returned the updated value by the function.

Operating on Embedded Documents Using the findOneAndUpdate() and findAndModify() Functions

In this example, I will use both functions and operate on an embedded document.

Using findOneAndUpdate() Function

Let’s say Whiskers has got along well with dogs now and we no more want to denounce him for not being a dog-friendly kitty. We will dot notation to access these embedded document fields.

> 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"
        ]
}

Looks like the function was successful. Let us take a look:

> 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() Function

Let us change the cost of Krissy to 23000.

> 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 this tutorial, we have learned to use the findOneAndUpdate() and findAndModify() functions in MongoDB. Both functions are used to select matching documents on the basis of some given condition and update the very first document accordingly. Hope this tutorial helps you in understanding them better.

References

https://docs.mongodb.com/v4.4/reference/method/db.collection.findAndModify/

https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate/

Aneesha S
Aneesha S
Articles: 172