Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get back the new value after an update in a embedded array?

Given the following MongoDB collection:

{
    "_id": ObjectId("56d6a7292c06e85687f44541"),
    "name": "My ranking list",
    "rankings": [
        {
            "_id": ObjectId("46d6a7292c06e85687f55542"),
            "name": "Ranking 1",
            "score": 1
        },
        {
            "_id": ObjectId("46d6a7292c06e85687f55543"),
            "name": "Ranking 2",
            "score": 10
        },
        {
            "_id": ObjectId("46d6a7292c06e85687f55544"),
            "name": "Ranking 3",
            "score": 15
        },
    ]
}

Here is how I increase the score of a given ranking:

db.collection.update(
    { "_id": ObjectId("56d6a7292c06e85687f44541"), "rankings._id" : ObjectId("46d6a7292c06e85687f55543") },
    { $inc : { "rankings.$.score" : 1 } }
);

How do I get the new score value? In the previous query I increase the second ranking from 10 to 11... How do I get this new value back after the update?

like image 816
j3d Avatar asked Mar 11 '16 18:03

j3d


People also ask

How do you update an array element in MongoDB?

You can use the updateOne() or updateMany() methods to add, update, or remove array elements based on the specified criteria. It is recommended to use the updateMany() method to update multiple arrays in a collection.

How do I update a nested array in MongoDB?

Update Nested Arrays in Conjunction with $[]The $[<identifier>] filtered positional operator, in conjunction with the $[] all positional operator, can be used to update nested arrays. The following updates the values that are greater than or equal to 8 in the nested grades. questions array if the associated grades.

How do you use findOneAndUpdate?

Getting Started. You need at least 2 parameters to call findOneAndUpdate() : filter and update . MongoDB finds the first document that matches filter and applies update . By default, findOneAndUpdate() returns the document as it was before MongoDB applied update .

How do I add values to an array in MongoDB?

In MongoDB, you can use the $push operator to append a value to an array. This operator can be used with various modifiers, one of which is the $position modifier. The $position modifier allows you to specify the position within the array that you want to insert the new value.


1 Answers

If you are on MongoDB 3.0 or newer, you need to use the .findOneAndUpdate() and use projection option to specify the subset of fields to return. You also need to set returnNewDocument to true. Of course you need to use the $elemMatch projection operator here because you cannot use a positional projection and return the new document.

As someone pointed out:

You should be using .findOneAndUpdate() because .findAndModify() is highlighed as deprecated in every official language driver. The other thing is that the syntax and options are pretty consistent across drivers for .findOneAndUpdate(). With .findAndModify(), most drivers don't use the same single object with "query/update/fields" keys. So it's a bit less confusing when someone applies to another language to be consistent. Standardized API changes for .findOneAndUpdate() actually correspond to server release 3.x rather than 3.2.x. The full distinction being that the shell methods actually lagged behind the other drivers ( for once ! ) in implementing the method. So most drivers actually had a major release bump corresponding with the 3.x release with such changes.

db.collection.findOneAndUpdate( 
    { 
        "_id": ObjectId("56d6a7292c06e85687f44541"), 
         "rankings._id" : ObjectId("46d6a7292c06e85687f55543") 
    },  
    { $inc : { "rankings.$.score" : 1 } },  
    { 
        "projection": { 
            "rankings": { 
                "$elemMatch": { "_id" : ObjectId("46d6a7292c06e85687f55543") } 
            }
        }, 
        "returnNewDocument": true 
    }
)

From MongoDB 3.0 onwards, you need to use findAndModify and the fields options also you need to set new to true in other to return the new value.

db.collection.findAndModify({   
    query: { 
        "_id": ObjectId("56d6a7292c06e85687f44541"), 
        "rankings._id" : ObjectId("46d6a7292c06e85687f55543") 
    },     
    update: { $inc : { "rankings.$.score" : 1 } },       
    new: true,  
    fields: { 
        "rankings": { 
            "$elemMatch": { "_id" : ObjectId("46d6a7292c06e85687f55543") }
        }  
    }
})

Both queries yield:

{
        "_id" : ObjectId("56d6a7292c06e85687f44541"),
        "rankings" : [
                {
                        "_id" : ObjectId("46d6a7292c06e85687f55543"),
                        "name" : "Ranking 2",
                        "score" : 11
                }
        ]
}
like image 95
styvane Avatar answered Sep 17 '22 23:09

styvane