2
{
    "_id" : "abcd",
    "arrayItems" : [
        {
            "name" : "Peter",
            "age" : 23,
            "profession" : "Student"
        },
        {
            "name" : "Paul",
            "age" : 80
            "profession" : "Student"
        },
        {
            "name" : "Mary",
            "age" : 45
            "profession" : "CEO"
        }
    ]
}

Is it possible to update in a single step? Peter-> "age" : 27 and Paul -> "age" : 23

In single steps I could do something like this

db.students.update({'_id':'abcd', 'arrayItems.name': 'Peter'}, {$set:{'arrayItems.$.age': 27}});
3

The short answer here is no, at least if you want to match and not just set specific elements (rather than looking to match multiple elements), something like this:

> db.students.findOne()
{
    "_id" : "abcd",
    "arrayItems" : [
        {
            "name" : "Peter",
            "age" : 23,
            "profession" : "Student"
        },
        {
            "name" : "Paul",
            "age" : 80,
            "profession" : "Student"
        },
        {
            "name" : "Mary",
            "age" : 45,
            "profession" : "CEO"
        }
    ]
}
> db.students.update(
    { "_id" : "abcd"}, 
    { $set: {"arrayItems.0.age": 27, "arrayItems.1.age" : 23 }}
  );
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.students.findOne()
{
    "_id" : "abcd",
    "arrayItems" : [
        {
            "name" : "Peter",
            "age" : 27,
            "profession" : "Student"
        },
        {
            "name" : "Paul",
            "age" : 23,
            "profession" : "Student"
        },
        {
            "name" : "Mary",
            "age" : 45,
            "profession" : "CEO"
        }
    ]
}

Unfortunately, unlike this simple test, with real usage there is no guarantee that the array you are updating has the structure you think it does, even if you fetch it immediately beforehand there is always the chance that someone updates between the read and your update.

In order for this to work you need SERVER-1243 to be implemented, and that is not currently planned for an imminent release. Here is the current statement on that lack of capability from MongoDB (as of Jun 2016) from that ticket:

MongoDB appreciates the challenge of maintaining applications utilizing schemas with large arrays, especially with respect to updating many or all array elements, and we very much recognize the interest from the community around this ticket.

Unfortunately, to implement such a major feature there are serious requirements:

  • a specification for new language features (like update modifiers or expressions), since we cannot break existing uses
  • should be included with support to match all array elements, as well was those matching a query
  • requests for support to update the last element(s) could be considered.
  • must support all existing update modifiers (correctly, and in a non-backwards-breaking way) $rename, $set, $unset, $pull, $push, $bit...
  • must work efficiently with all arrays, including those having thousands of elements
  • cannot change current update semantics or behaviors which existing applications and deployments depend on (non-backwards-breaking).

In summary, adding this as a new feature, or improvement, is not trivial. It will require resources which are currently working on other projects, and in short is a matter of prioritization over other parts of the whole server.

As you can infer from the age of the ticket and the lengthy discussion, this has come up many times and there are plenty of workarounds in the ticket and elsewhere but (as yet) there is no built-in method to achieve this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.