2011-01-03 3 views
82
{ 

     "_id" : ObjectId("4d1cb5de451600000000497a"),   
     "name" : "dannie", 
     "interests" : [ 
      "guitar", 
      "programming",   
      "gadgets", 
      "reading" 
     ] 
} 

В приведенном выше примере, предположим, что вышеуказанный документ находится в db.people коллекции. Как удалить 3-й элемент из интересов массив от него индекс?В MongoDB, как удалить элемент массива по его индексу

Edit:

Это мое текущее решение:

var interests = db.people.findOne({"name":"dannie"}).interests; 
interests.splice(2,1) 
db.people.update({"name":"dannie"}, {"$set" : {"interests" : interests}}); 

Есть ли более прямой путь?

+0

https://docs.mongodb.org/manual/reference/operator/update/pull/ – userMod2

ответ

114

Нет прямого способа вытягивания/удаления по индексу массива. На самом деле, это открытый вопрос http://jira.mongodb.org/browse/SERVER-1014, вы можете проголосовать за него.

Обходной использует $ отключенное и затем $ тянуть:

db.lists.update({}, {$unset : {"interests.3" : 1 }}) 
db.lists.update({}, {$pull : {"interests" : null}}) 

обновление: как указано в некоторых комментариях этот подход не является атомарной и может вызвать некоторые условия гонки, если другие клиенты чтения и/или записи между двумя операциями. Если нужна операция, чтобы быть атомарным, мы могли бы:

  • Прочитайте документ из базы данных
  • обновить документ и удалить элемент в массиве
  • Заменить документ в базе данных. Для того, чтобы обеспечить документ не изменился, так как мы читаем, мы можем использовать обновление, если текущий шаблон описывается in the mongo docs
+27

Это было полтора года? Это все еще состояние вещей с монгодбом? – Abe

+0

Следующий ответ более прямой и работал для меня. Хотя он не удаляется по индексу, а скорее удаляется по значению. – vish

+1

@Javier - не будет ли это решение оставить вас открытым для вопросов, если db изменилось между тем временем, когда вы подсчитали позицию в индексе, и временем, которое вы отменили? – UpTheCreek

18

Вы можете использовать $pull модификатор update операций для удаления конкретного элемента в массиве. В случае, если Вы предоставили запрос будет выглядеть следующим образом:

db.people.update({"name":"dannie"}, {'$pull': {"interests": "guitar"}}) 

Кроме того, вы можете рассмотреть возможность использования $pullAll для удаления всех вхождений. Подробнее об этом на странице официальной документации - http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull

Это не использует индекс в качестве критерия для удаления элемента, но может помочь в случаях, подобных вашим. IMO, используя индексы для адресации элементов внутри массива, не очень надежна, поскольку mongodb не согласуется с порядком элементов как fas, как я знаю.

+5

Его элемент представляет собой массив в вопросе. В этом случае Монго в порядке. Фактически, все документы представляют собой упорядоченные коллекции, но многие драйверы не обрабатывают их таким образом. Дальнейшее усложнение вопроса, если документ должен быть перемещен после операции обновления (из-за роста за пределами коэффициента заполнения), порядок ключей внезапно становится в алфавитном порядке (под обложками, я думаю, они отсортированы по их двоичному значению, это подозрение основанный на моих знаниях о том, что массивы представляют собой довольно стандартные документы с ключами, которые являются целыми целыми числами вместо строк). – marr75

+0

Это позволяет избежать проблем с установкой unset + pull, но требует строгого упорядочения вашего словаря. Словарь на большинстве языков неупорядочен, поэтому может быть больно, чтобы это произошло. –

+0

@ marr75: У вас есть ссылка? Монгольские документы всегда должны сохранять порядок, и если они когда-либо переупорядочивают поддокументы, многие вещи сломаются. –

2

Я бы рекомендовал использовать поле GUID (я обычно использую ObjectID) или поле автоматического увеличения для каждого поддокумента в массиве.

С помощью этого GUID легко вывести $ pull и убедиться, что правильный будет вытащен. То же самое касается других операций с массивами.

0

Вместо того, чтобы использовать отмену (как в принятом ответе), я решаю это, установив поле в уникальное значение (т. Е. Не 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}}); 

Надеюсь Монго будет решить эту проблему, возможно, за счет расширения модификатор $ позиции для поддержки $ тянуть, а также $ толчок.

1

Вместо использования $ pull мы можем использовать $ pop для удаления элементов в массиве по его индексу. Но вы должны вычесть 1 из позиции индекса для удаления на основе индекса.

Для Например, если вы хотите удалить элемент с индексом 0, вы должны использовать -1, для индекса 1, вы должны использовать 0 и так далее ...

Запрос для удаления третьего элемента (устройства):

db.people.update({"name":"dannie"}, {'$pop': {"interests": 1}})

для справки: https://docs.mongodb.com/manual/reference/operator/update/pop/

+0

Согласно связанной документации, '$ pop' может удалить только первый или последний элемент из массива. Запрос в этом ответе не удаляет третий элемент. –