7

Want to upsert in object properties in a array of a document

Consider a document in collection m

{ "_id" : ObjectId("524bfc39e6bed5cc5a9f3a33"), 
 "x" : [       
    { "id":0.0, "name":"aaa"},{ "id":1.0, "name":"bbb"}  
 ]
}

Want to add age:100 to { "id":0.0, "name":"aaa"} . Not just age .. But but provision for upsert in the array element {}. So it can contain {age:100,"city":"amd"} (since i am getting this from the application service)

Was trying this... But did not worked as it replaced the entire array element

db.m.update({_id:ObjectId("524bfc39e6bed5cc5a9f3a33"),
     "x" : {
                "$elemMatch" : {
                        "id" : 0.0
                }
}},
{
        $set : {
                "x.$" : {
                    "age": 100
            }
        }
},
{upsert: true}
)

Changed the document to (which i did not wanted)

 { "_id" : ObjectId("524bfc39e6bed5cc5a9f3a33"), 
     "x" : [       
        { "age":100},{ "id":1.0, "name":"bbb"}  
     ]
    }

Is this possible without changing schema.

shrw
  • 1,719
  • 5
  • 27
  • 50

2 Answers2

7
$set : {"x.$" : {"age": 100}}

x.$ sets the entire matched array element to {age: 100}

This should work:

db.m.update({_id:ObjectId("524bfc39e6bed5cc5a9f3a33"),
"x.id": 0.0}, {$set: {"x.$.age": 100 }});

Using elemMatch:

db.test.update({x: {$elemMatch: {id: 1}}},{$set:  {"x.$.age": 44}})

Note that the upsert option here, is redundant and wouldn't work if the id isn't present in x because the positional operator $ doesn't support upserting.

c.P.u1
  • 16,664
  • 6
  • 46
  • 41
  • I know this works. But i am asking if db.test.update({x: {$elemMatch: {id: 1}}},{$set: {"x.$":{"a":100,"b":200,"age": 44}}}) would work ?? Or something similar works . Note {"a":100,"b":200,"age": 44} could be object and it should "upsert" values in the matched item of the array. – shrw Oct 02 '13 at 12:35
  • Yes, but it'll **replace** the entire matched element with the new document: `{"a":100,"b":200,"age": 44}`. And it cannot `upsert` values because an `upsert` is performed only if a match isn't found(an element in `x` isn't present with the specified `id`). – c.P.u1 Oct 02 '13 at 12:45
  • >>upsert is performed only if a match isn't found,, nah! on matched documents properties are updated/ inserted – shrw Oct 02 '13 at 12:49
  • This is from the MongoDB docs: **If set to true, creates a new document when no document matches the query criteria. The default value is false, which does not insert a new document when no match is found.** – c.P.u1 Oct 02 '13 at 12:51
  • also if you try to update with upsert set, you are adding to the properties; and not replacing the document. – shrw Oct 03 '13 at 08:46
  • Yes, bro. What I was trying to say is that if you know, in advance, that a match will be found, then specifying the `upsert` option is redundant. `upsert` = update the matched document or insert a new one if a match isn't found. – c.P.u1 Oct 03 '13 at 09:00
  • 2
    Using of $ is not possible via upsert according to official docs: https://docs.mongodb.com/manual/reference/operator/update/positional/ – Alireza Mohamadi Dec 24 '16 at 17:29
0

This is not possible without changing schema. If you can change schema to use an object to store your items (rather than an array), you can follow the approach I outlined in this answer.

Community
  • 1
  • 1
G-Wiz
  • 7,370
  • 1
  • 36
  • 47