32

I have a document that looks like this:

{
    "_id": 3,
    "Slug": "slug",
    "Title": "title",
    "Authors": [
        {
            "Slug": "slug",
            "Name": "name"
        }
    ]
}

I want to update all Authors.Name based on Authors.Slug. I tried this but it didn't work:

.update({"Authors.Slug":"slug"}, {$set: {"Authors.Name":"zzz"}});

What am I doing wrong here?

Riccardo Galli
  • 12,419
  • 6
  • 64
  • 62
ajma
  • 12,106
  • 12
  • 71
  • 90
  • 1
    "{ "_id" : 3, "Slug" : "slug", "Title" : "title", "Authors" : [ "Slug" : "slug", "Name" : "name"] }" is not a valid document. If you provide example data then provide *working* example data. –  Jul 20 '11 at 07:23
  • 1
    I missed some curly braces. it's a valid document now. – ajma Jul 20 '11 at 07:25
  • 1
    Dude, also your update does not work...do you want to waste our time?> db.foo.update({"Authors.Slug":"slug"}, {$set: {"Authors.Name":"zzz"}}) can't append to array using string field name [Name] –  Jul 20 '11 at 07:27
  • 3
    that's my question. I want to know why the update doesn't work – ajma Jul 20 '11 at 07:27
  • 3
    look at the "positional operator" and $elemMatch –  Jul 20 '11 at 07:29
  • 2
    the positional operator was what I needed. this is what works for the update: .update({"Authors.Slug":"slug"}, {$set: {"Authors.$.Name":"zzz"}}); – ajma Jul 20 '11 at 07:34

3 Answers3

61
.update(Authors:{$elemMatch:{Slug:"slug"}}, {$set: {'Authors.$.Name':"zzz"}});
Andrew Orsich
  • 52,935
  • 16
  • 139
  • 134
Remon van Vliet
  • 18,365
  • 3
  • 52
  • 57
  • 2
    You don't need to use elemMatch to do this. It's the "$" in the 2nd part that does the trick. See here: http://www.mongodb.org/display/DOCS/Updating/#Updating-The%24positionaloperator – Sean Clark Hess Aug 06 '12 at 18:45
  • 3
    Not necessarily true. The query part must uniquely identify an array element for the positional operator and {Authors.Slug:"slug"} is not semantically equivalent to the $elemMatch version. The $elemMatch version does partial matching even if you have more than one field in the same element to match making it the superior method to do these things. – Remon van Vliet Aug 07 '12 at 09:00
  • 4
    I know it's an old answer, but I am having trouble _really_ understanding the difference between queries made with $elemMatch and their "normal" equivalent (like above). What do you mean by "The $elemMatch version does partial matching even if you have more than one field in the same element to match" ? – Merc Feb 25 '13 at 03:11
  • 14
    @Merc : Say the elements in your array have fields "a" and fields "b" : arr:[{a:1, b:1}, {a:2, b:10}, ..]. In that case arr:{$elemMatch:{a:1}} would match the first element (the element has a field "a" with value 1) bit arr:{a:1} would not (the element is {a:1, b:1} and not {a:1}. In other words, without $elemMatch the entire element in the array should match rather than a specific set of fields. – Remon van Vliet Feb 26 '13 at 10:07
  • 1
    @Merc you're very welcome. A more detailed explanation is in the documentation here : http://docs.mongodb.org/manual/reference/operator/elemMatch/ – Remon van Vliet Feb 26 '13 at 14:44
  • This page on the ["$" positional operator](https://www.mongodb.com/docs/manual/reference/operator/update/positional/) has all the needed details. – Akaisteph7 Aug 08 '22 at 15:19
2

You can use update with array filters:
https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#positional-update-arrayfilters

Probably something like this:

yourcollection.update(
{},
{
    "$set": {
        "Authors.$[element].Name": "zzz"
    }
},
{
    "multi": true,
    "arrayFilters": [
         { "element.Slug": "slug" }
    ]
}
)

Ps.: it will not work in Robo3T as explained here: Mongodb 3.6.0-rc3 array filters not working? However, you can try on a mongo shell with version >= 3.6.

Rock
  • 21
  • 4
0

yes, Rock's solution is working, P.S Notes is really helpful when trying Robo31.. If we want to update all db.collection_name.update({}, {$set: {"Authors.$[].Name": "zzz"}})

If we want to update with matching object in an array db.collection_name.update({}, {$set: {"Authors.$[i].Name": "zzz"}}, {arrayFilters: [{"i.Slug": "slug"}]})

Ref: https://jira.mongodb.org/browse/SERVER-1243

joel Raja
  • 59
  • 5