2014-03-30 5 views
1

Облицовка проблемы при попытке обновить элемент в массиве вспомогательного документа в Mongo. Если я считаю, что следующий документ в коллекции «ресурс»Как обновить элемент в массиве поддокумента в Mongodb

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

Я хочу обновить "item4" с каким-либо другим значением, как "item5" для "resource_id" = 2

Следующий оператор дал мне ошибку: Не удается применить позиционный оператор без соответствующего поля запроса, содержащего массив.

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

Любая помощь по этому вопросу будет высоко оценен.

ответ

1

Оператор позиционирования может использоваться только один раз в запросе. Это ограничение, есть открытый билет для улучшения: https://jira.mongodb.org/browse/SERVER-831

Другим способом решения этой проблемы может быть нажатие «item5» на массив и потянуть «item4». Что-то вроде этого:

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

Однако это не возможно, либо, $pull и $push не могут быть использованы в том же запросе для того же поля. Связанный билет: https://jira.mongodb.org/browse/SERVER-1050

Я вижу два решения. Один из них заключается в выполнении двух запросов. В первом запросе, вы нажимаете «Item5», во втором запросе вы тянете «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" } }); 

Если вы хотите сделать это в одном запросе, вы можете использовать Монго оболочку. Что-то вроде этого:

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); 
    } 
    } 
}) 
+0

Благодаря Gergő для Вашего ответа на это. Это было действительно полезно, чтобы избежать более чем одного утверждения для этой операции, я немного изменил свою модель. Еще раз спасибо за вашу помощь по этому поводу – user3315068

0

символ $ изменяет только последнюю позицию последнего массива в поиске, и вы можете использовать $addToSet или $push для добавлений элементов ...

> 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" ] } ] } 

Но лучше бежать два запроса в одно и то же время?

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

поле дублирования имени не допускается с модификаторами

+0

Спасибо Карлосу за ваш ответ, я не пробовал $ addToSet, но пробовал $ push и $ pull в тех же запросах, но это не сработало. Вы говорите, что вместо $ push, если я использую $ addToSet, тогда он должен работать? – user3315068

+0

Нет, MongoDB говорит, что ** «Дублирование имени не допускается с помощью модификаторов» **, в кратком слове, MongoDB не разрешает удалять и добавлять значение в том же виде в одном поле. –