Удалить поле из всех элементов массива в mongodb
У меня есть документ ниже в MongoDB (2.4.5)
{
"_id" : 235399,
"casts" : {
"crew" : [
{
"_id" : 1186343,
"withBase" : true,
"department" : "Directing",
"job" : "Director",
"name" : "Connie Rasinski"
},
{
"_id" : 86342,
"withBase" : true
}
]
},
"likes" : 0,
"rating" : 0,
"rating_count" : 0,
"release_date" : "1955-11-11"
}
Я хочу удалить withBase, поданный из элементов массива внутри casts.crew..
Я пробовал это
db.coll.update({_id:235399},{$unset: { "casts.crew.withBase" : 1 } },false,true)
ничего не изменилось.
И попробовал это..
db.coll.update({_id:235399},{$unset: { "casts.crew" : { $elemMatch: { "withBase": 1 } } } },false,true)
он удалил весь массив экипажа из документа.
Может кто-нибудь, пожалуйста, предоставит мне правильный запрос?
Ответы
Ответ 1
Извините, что разочаровал вас, но ваш ответ
db.coll.update({
_id:235399,
"casts.crew.withBase": {$exists: true}
},{
$unset: {
"casts.crew.$.withBase" : true
}
},false,true)
неверно. Фактически он удалит значение, но только с первого вхождения вложенного документа, из-за того, что оператор позиционирования работает:
оператор positional $действует как заполнитель для первого элемента который соответствует документу запроса
Вы также не можете использовать $unset
(как вы пробовали раньше), потому что он не может работать с массивами (и вы в основном пытаетесь удалить ключ из документа из массива). Вы также не можете удалить его с помощью $pull
, потому что pull удаляет весь массив, а не только его поле.
Поэтому, насколько я знаю, вы не можете сделать это с помощью простого оператора. Поэтому последнее средство делает $find
, а затем forEach
с сохранением. Вы можете увидеть как это сделать в моем ответе здесь. В вашем случае вам нужно иметь еще один цикл в функции forEach
для итерации по массиву и удалить ключ. Я надеюсь, что вы сможете изменить его. Если нет, я постараюсь вам помочь.
P.S. Если кто-то ищет способ сделать это - вот функция Сандры
db.coll.find({_id:235399}).forEach( function(doc) {
var arr = doc.casts.crew;
var length = arr.length;
for (var i = 0; i < length; i++) {
delete arr[i]["withBase"];
}
db.coll.save(doc);
});
Ответ 2
Я нашел способ отключить эти списки, не вытягивая объект (это означает, что он просто выполняет обновление), он довольно хакерский, но если у вас есть огромная база данных, он заключит сделку:
db.coll.update({},{$unset: {"casts.crew.0.withBase" : 1, "casts.crew.1.withBase" : 1} }, {multi: 1})
Другими словами, вам нужно рассчитать, сколько объектов может быть в любом из ваших списков документов и явно добавить эти числа, в этом случае как {casts.crew.NUMBER.withBase: 1}
.
Кроме того, чтобы подсчитать самый длинный массив в объекте mongodb, можно сделать агрегат, например:
db.coll.aggregate( [ { $unwind : "$casts.crew" }, { $group : { _id : "$_id", len : { $sum : 1 } } }, { $sort : { len : -1 } }, { $limit : 1 } ], {allowDiskUse: true} )
Просто хочу подчеркнуть, что это не просто решение, но способ быстрее, чем выборка и сохранение.
Ответ 3
Вы можете использовать новый позиционный идентификатор для обновления нескольких элементов в массиве.
Что-то вроде
db.coll.update( {_id:235399}, {$unset: {"casts.crew.$[].withBase":""}} )
$[] удаляет все свойство withBase
из массива crews
. Он выступает в качестве заполнителя для обновления всех элементов в массиве.
Использовать multi true для воздействия на несколько документов.