56

I have this collection:

[{ "_id" : 7,
   "category" : "Festival",
   "comments" : [
        {
                "_id" : ObjectId("4da4e7d1590295d4eb81c0c7"),
                "usr" : "Mila",
                "txt" : "This is a comment",
                "date" : "4/12/11"
        }
    ]
}]

All I want is to push insert a new field inside comments like this:

[{ "_id" : 7,
   "category" : "Festival",
   "comments" : [
        {
                "_id" : ObjectId("4da4e7d1590295d4eb81c0c7"),
                "usr" : "Mila",
                "txt" : "This is a comment",
                "date" : "4/12/11",
                "type": "abc"  // find the parent doc with id=7 & insert this inside comments
        }
    ]
}]

How can I insert inside the comments subdocument?

Tolga Evcimen
  • 7,112
  • 11
  • 58
  • 91
kheya
  • 7,546
  • 20
  • 77
  • 109

2 Answers2

95

You need to use the $ positional operator

For example:

update({ 
       _id: 7, 
       "comments._id": ObjectId("4da4e7d1590295d4eb81c0c7")
   },{
       $set: {"comments.$.type": abc}
   }, false, true
);

I didn't test it but i hope that it will be helpful for you.

If you want to change the structure of document you need to use

db.collection.update( criteria, objNew, upsert, multi )

Arguments:

criteria - query which selects the record to update;
objNew - updated object or $ operators (e.g., $inc) which manipulate the object
upsert - if this should be an "upsert"; that is, if the record does not exist, nsert it
multi - if all documents matching criteria should be updated

and insert new objNew with new structure. check this for more details

Roman
  • 107
  • 1
  • 1
  • 7
Andrei Andrushkevich
  • 9,905
  • 4
  • 31
  • 42
  • 1
    This dont work for me. it just updates ONE item inside the array, not all. even though I passed true for multiple – Hitesh Joshi Sep 30 '12 at 22:35
  • 1
    Didn't work for me either. It works if I set new_comments.type but when I try to modify and existing parent like comments it doesn't work – Cilvic Sep 22 '13 at 13:58
  • 3
    Note that since MongoDB ver 2.2 syntax for update is db.collection.update( , , { upsert: , multi: } ) – Michal Feb 02 '14 at 10:08
  • 1
    Docs seem to have changed. This goes over positionals: https://docs.mongodb.com/manual/reference/operator/update/positional/ – RandomInsano Sep 22 '17 at 14:52
3

The $ positional operator is only going to work as expected if the 'comments' field is NOT an array. The OP's json is malformed, but it looks like it could be an array.

The issue is that mongodb right now will only update the first element of an array which matches the query. Though there is an RFE open to add support for updating all matching array elements: https://jira.mongodb.org/browse/SERVER-1243

To work around this issue with arrays you just have to do a regular find then update the elements in the array individually.