Pregunta

Facing issue while trying to update an element within an array of sub document in Mongo. If I consider the following document in the collection "resource"

{
    "_id": 1,
    "resources": [
        {
            "resource_id": 1,
            "resource_list": ["item1","item2"]
        },
        {
            "resource_id": 2,
            "resource_list": ["item4","item3"]
        }
    ]
}

I want to update "item4" with some other value like "item5" for "resource_id" = 2

The following statement gave me an error : Cannot apply the positional operator without a corresponding query field containing an array.

db.resource.update({"resources.resource_id": 2, "resources.resource_list": "item4"}, {$set: {"resources.$.resource_list.$": "item5"}})

Any help on this will be highly appreciated.

¿Fue útil?

Solución

The positional operator can be used only once in a query. This is a limitation, there is an open ticket for improvement: https://jira.mongodb.org/browse/SERVER-831

An other way to solve this problem could be to push "item5" to the array and pull "item4". Something like this:

db.resource.update({ "resources.resource_id": 2, "resources.resource_list": "item4" }, { $pull: { "resources.$.resource_list": "item4" }, $push: { "resources.$.resource_list": "item5" } })

However this isn't possible either, $pull and $push can't be used in the same query for the same field. Related ticket: https://jira.mongodb.org/browse/SERVER-1050

I see two solutions. One is to execute two queries. In the first query, you push "item5", in the second query you pull "item4":

db.resource.update({ "resources.resource_id": 2, "resources.resource_list": "item4" }, { $push: { "resources.$.resource_list": "item5" } });
db.resource.update({ "resources.resource_id": 2, "resources.resource_list": "item4" }, { $pull: { "resources.$.resource_list": "item4" } });

If you want to do it in one query, you can use mongo shell. Something like this:

db.resource.find({ 'resources.resource_id': 2, 'resources.resource_list': 'item4' }).forEach( function(document) {
  for (var i in document.resources) {
    if (document.resources[i].resource_id == 2) {
      var index = document.resources[i].resource_list.indexOf('item4');
      document.resources[i].resource_list[index] = 'item5';
      db.resource.save(document);
    }
  }
})

Otros consejos

symbol $ only modifies the last position of the last array in the search, and you can use $addToSet or $push for add items...

 > db.resource.find()
    { "_id" : 1, 
      "resources" : [
                     { "resource_id" : 1,   
                       "resource_list" : [ "item1","item2" ] },     
                     { "resource_id" : 2, 
                       "resource_list" : [ "item4", "item3" ] } ] }

    > db.resource.update({"resources.resource_id": 2, 
                          "resources.resource_list": "item4"},
                         {$addToSet:{"resources.$.resource_list": "item5"}})

    > db.resource.find()
    { "_id" : 1, "resources" : [
                             { "resource_id" : 1, 
                               "resource_list" : [ "item1", "item2" ] },
                             { "resource_id" : 2, 
                               "resource_list" : [ "item4", "item3", "item5" ] } ] }

    > db.resource.update({"resources.resource_id": 2, 
                          "resources.resource_list": "item4"},
                         {$pull: {"resources.$.resource_list": "item4"}})

    > db.resource.find()
    { "_id" : 1, "resources" : [ 
                               { "resource_id" : 1,
                                 "resource_list" : [ "item1", "item2" ] },
                               { "resource_id" : 2,
                                 "resource_list" : [ "item3","item5" ] } ] }

But is better run two querys in same time?

> db.algo.update({"resources.resource_id": 2,
                  "resources.resource_list": "item4"}, 
                 {$addToSet:{"resources.$.resource_list": "item5"},
                   $pull: {"resources.$.resource_list": "item4"}})

Field name duplication not allowed with modifiers

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top