#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:
Ответ №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 удаляет весь объект и, следовательно, не является семантически эквивалентным…