В mongoDb, как удалить элемент массива по его индексу
{
"_id" : ObjectId("4d1cb5de451600000000497a"),
"name" : "dannie",
"interests" : [
"guitar",
"programming",
"gadgets",
"reading"
]
}
В приведенном выше примере предположим, что указанный выше документ находится в коллекции db.people. Как удалить третий элемент массива интересов с помощью index?
Edit:
Это мое текущее решение:
var interests = db.people.findOne({"name":"dannie"}).interests;
interests.splice(2,1)
db.people.update({"name":"dannie"}, {"$set" : {"interests" : interests}});
Есть ли более прямой способ?
Ответы
Ответ 1
Нет прямого способа вытягивания/удаления по индексу массива. Фактически, это открытый вопрос http://jira.mongodb.org/browse/SERVER-1014, вы можете проголосовать за него.
В обходном пути используется $unset, а затем $pull:
db.lists.update({}, {$unset : {"interests.3" : 1 }})
db.lists.update({}, {$pull : {"interests" : null}})
Обновление: как упоминалось в некоторых комментариях, этот подход не является атомарным и может вызвать некоторые условия гонки, если другие клиенты читают и/или записывают между двумя операциями. Если нам нужна операция, чтобы быть атомарной, мы могли бы:
- Прочитайте документ из базы данных
- Обновите документ и удалите элемент в массиве
- Заменить документ в базе данных. Для того, чтобы обеспечить документ не изменился, так как мы читаем, мы можем использовать обновление, если текущий шаблон описывается в Монго документы
Ответ 2
Вы можете использовать модификатор $pull
операции update
для удаления определенного элемента в массиве. Если вы предоставили запрос, он будет выглядеть так:
db.people.update({"name":"dannie"}, {'$pull': {"interests": "guitar"}})
Кроме того, вы можете использовать $pullAll
для удаления всех вхождений. Подробнее об этом на странице официальной документации - http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull
Это не использует индекс в качестве критерия для удаления элемента, но может помочь в случаях, подобных вашим. IMO, используя индексы для адресации элементов внутри массива, не очень надежна, поскольку mongodb не согласован в порядке элементов, как я знаю.
Ответ 3
Я бы рекомендовал использовать поле GUID (я обычно использую ObjectID) или поле автоматического увеличения для каждого поддокумента в массиве.
С помощью этого GUID легко вывести $pull и убедиться, что правильный будет вытащен. То же самое касается других операций с массивами.
Ответ 4
Вместо того, чтобы использовать отмену (как в принятом ответе), я решаю это, установив для поля уникальное значение (т.е. не NULL), а затем сразу же вытащив это значение. Немного безопаснее с асинхронной перспективы. Вот код:
var update = {};
var key = "ToBePulled_"+ new Date().toString();
update['feedback.'+index] = key;
Venues.update(venueId, {$set: update});
return Venues.update(venueId, {$pull: {feedback: key}});
Надеюсь, монго рассмотрит это, возможно, расширив модификатор $position, чтобы поддерживать $pull, а также $push.
Ответ 5
Вместо использования $pull мы можем использовать $pop для удаления элементов в массиве по его индексу. Но вы должны вычесть 1 из позиции индекса для удаления на основе индекса.
Например, если вы хотите удалить элемент в индексе 0, вы должны использовать -1, для индекса 1 вы должны использовать 0 и так далее...
Запрос для удаления третьего элемента (гаджеты):
db.people.update({"name":"dannie"}, {'$pop': {"interests": 1}})
для справки: https://docs.mongodb.com/manual/reference/operator/update/pop/