Как мне обновить / установить / отменить ключ во встроенном документе / массиве в MongoDB?

#mongodb

#mongodb

Вопрос:

Я пытаюсь отменить все значения в документе, который встроен в массив. Допустим, у меня есть коллекция coll с массивом things , содержащая значение myval . Я хочу отменить myval . Это выглядит так:

 { things: [{ myval: 1 }, { myval: 2 }] }
  

Я пробовал оба

 db.coll.update({}, {$unset: {'things.myval': 1}})
  

и

 db.coll.things.update({}, {$unset: {'myval': 1}})
  

Ни один из них не работает. Я не могу найти в Интернете никакой документации, описывающей, как это сделать.

Ответ №1:

Я наткнулся на это и был разочарован, увидев, что для этого нужно было использовать только вложенный forEach. Итак, после некоторых поисков я нашел другой способ! Начиная с версии 3.6 mongo, существует all positional operator ( $[] ) (версия 3.6 была введена после того, как был задан этот вопрос … и даже после того, как он был последним активным, НО если кто-нибудь еще столкнется с этим)

Чтобы удалить столбец myval из первого встроенного документа, выполните следующие действия:

 db.coll.update(
  {things: {'$exists': true}},
  {$unset: {'things.$[].myval': 1}}
)
  

или, если вы хотите удалить его из всех соответствующих документов, используйте updateMany

 db.coll.updateMany(
  {things: {'$exists': true}},
  {$unset: {'things.$[].myval': 1}}
)
  

Он $unset будет редактировать его только в том случае, если значение существует, но оно не будет выполнять безопасную навигацию (т. Е. Сначала Оно не будет проверять, что оно существует), поэтому exists необходим для встроенного документа / массива.

Ответ №2:

Вы можете удалить значение из «массива», используя оператор $pull:

 db.coll.update({}, {$pull: {'things': {'myval': 1}}});
  

Также взгляните на документацию по $pull:

http://www.mongodb.org/display/DOCS/Updating#Updating-$pull

Ответ №3:

Должен работать с вашим первым подходом в соответствии с официальной документацией:

 db.coll.update({}, {$unset: {'things.myval': 1}})
  

Но у меня это не работает. Итак, решение, которое я нашел, примененное к вашему примеру, было:

 db.coll.find().forEach(function(o) {
    for(var i=0; i<o.things.length; i  ) {
        var unset = {};
        unset["things."   i   ".myval"] = "";
        db.coll.update( { "_id": o._id  }, { "$unset": unset } );
    }
})
  

Или с более функциональным стилем:

 db.coll.find().forEach(function(o) {
    o.things.forEach(function(t, i) {
        var unset = {};
        unset["things."   i   ".myval"] = "";
        db.coll.update( { "_id": o._id  }, { "$unset": unset } );
    })
})
  

Ответ №4:

Это не может работать, потому что селектор {}-empty выбирает более одного документа, а update обычно пытается обновить один документ.Чтобы заставить его работать, используйте флаг multi, чтобы сообщить mongo update, что отправляется более одного документа.

multi — указывает, следует ли обновлять все документы, соответствующие критериям, а не только один. Может быть полезно с помощью приведенных ниже операторов $.

 db.coll.update({}, {$unset: {'things.myval': 1}},false,true)
  

или

 db.coll.update({}, {$pull: {'things': {'myval': 1}}},false,true)
  

Попробуйте любой из них и увидите, какой из них работает, но вы должны использовать несколько параметров в обоих

Комментарии:

1. $unset не будет работать с объектами в массивах, а $ pull удаляет весь объект и, следовательно, не является семантически эквивалентным…