Johnny
Johnny

Reputation: 277

Update an element in sub of sub array in mongodb

I have this data in Mongo:

{
    "_id" : ObjectId("505fd43fdbed3dd93f0ae088"),
    "categoryName" : "Cat 1",
    "services" : [
        {
            "serviceName" : "Svc 1",
            "input" : [
                { "quantity" : 10, "note" : "quantity = 10" }, 
                { "quantity" : 20, "note" : "quantity = 20" }
            ]
        },
        {
            "serviceName" : "Svc 2",
            "input" : [
                { "quantity" : 30, "note" : "quantity = 30" }, 
                { "quantity" : 40, "note" : "quantity = 40" }
            ]
        }
    ]
}

Now I want to update a quantity for "Svc 1":

{ "quantity" : 10, "note" : "quantity = 10" }

Like:

{"quantity": 100, "note": "changed to 100"}

How can I do with Mongo?`

As I know, operational operator only supports for the first array, someone advised to use index of an element of the sub sub array, but the problem is that how can know that index at run time? (I'm using native C# driver of MongoDB)

Thanks in advance for your helps!

Johnny

Upvotes: 14

Views: 16072

Answers (2)

achuth
achuth

Reputation: 1212

Since you don't know the position of the value wanted to update, first insert a new value with updated information and then remove the value wanted to update.

db.services.update(
   {
    '_id' : ObjectId("505fd43fdbed3dd93f0ae088"),
    'services.serviceName' : 'Svc 1'
   },
   {
    { $addToSet: { 'services.$.input' : "new sub-Doc" }
   }
)

And then remove when insert is success

db.services.update(
   {
    '_id' : ObjectId("505fd43fdbed3dd93f0ae088"),
    'services.serviceName' : 'Svc 1'
   },
   {
    { $pull: { 'services.$.input' : { "quantity" : 10, "note" : "quantity = 10" } }
   }
)

This is useful when index is not known and document should have sub-documents having same key like "input" in post Update an element in sub of sub array in mongodb

Upvotes: 8

Stennie
Stennie

Reputation: 65333

Since you have an array within an array, there isn't any easy way to reference the nested subarray unless you know the position in the array you want to update.

So, for example, you could update the first input for 'Svc 1' with the C# equivalent of:

db.services.update(

    // Criteria
    {
        '_id' : ObjectId("505fd43fdbed3dd93f0ae088"),
        'services.serviceName' : 'Svc 1'
    },

    // Updates
    {
        $set : {
            'services.$.input.0.quantity' : 100,
            'services.$.input.0.note' : 'Quantity updated to 100'
        }
    }
)

If you don't know the position for the nested input array, you will have to fetch the matching services, iterate the input array in your application code, then $set the updated array.

Alternatively, you could modify your nested array to use an embedded document instead, eg:

{
    "categoryName" : "Cat 1",
    "services" : [
        {
            "serviceName" : "Svc 1",
            "input1" : { "quantity" : 10, "note" : "quantity = 10" }, 
            "input2" : { "quantity" : 20, "note" : "quantity = 20" }
        },
    ]
}

Which you could then update by name, eg input1:

db.services.update(

    // Criteria
    {
        '_id' : ObjectId("5063e80a275c457549de2362"),
        'services.serviceName' : 'Svc 1'
    },

    // Updates
    {
        $set : {
            'services.$.input1.quantity' : 100,
            'services.$.input1.note' : 'Quantity updated to 100'
        }
    }
)

Upvotes: 15

Related Questions