В 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/