Вставить в определенный индекс для массива mongo

Mongo поддерживает массивы документов внутри документов. Например, что-то вроде

{_id: 10, "coll": [1, 2, 3] }

Теперь представьте, что я хотел вставить произвольное значение при произвольном индексе

{_id: 10, "coll": [1, {name: 'new val'}, 2, 3] }

Я знаю, что вы можете обновлять значения с помощью $и $set, но ничего для вставки. это отстой, чтобы заменить весь массив только для вставки с определенным индексом.

Ответ 1

Начиная с версии 2.6, вы, наконец, можете это сделать. Вы должны использовать оператор $position. Для вашего конкретного примера:

db.students.update(
  { _id: 10},
  { $push: {
     coll: {
       $each: [ {name: 'new val'} ],
       $position: 1
     }
  }}
)

Ответ 2

Следующее выполнит трюк:

var insertPosition = 1;
var newItem = {name: 'new val'};

db.myCollection.find({_id: 10}).forEach(function(item)
{
    item.coll = item.coll.slice(0, insertPosition).concat(newItem, item.coll.slice(insertPosition));
    db.myCollection.save(item);
});

Если insertPosition является переменной (т.е. вы точно не знаете, куда вы хотите вставить его, но знаете, что хотите вставить его после элемента с name = "foo", просто добавьте цикл for() до item.coll =, чтобы найти insertPosition (и добавить 1 к нему, так как вы хотите вставить его ПОСЛЕ name = "foo").

Ответ 3

Удобный ответ (не выбран ответ, но самый высокий рейтинг) из этого похожего сообщения: У вас есть mongo $push preend вместо append?

использует $set для вставки 3 в первую позицию в массиве, называемый "array". Пример из соответствующего ответа Сергея Никитина:

db.test.update({"_id" : ObjectId("513ad0f8afdfe1e6736e49eb")}, 
                 {'$set': {'array.-1':     3}})

Ответ 4

Относительно вашего комментария:

Ну.. с параллельными пользователями это будет проблематично с любой базой данных...

Я бы сделал следующее: Добавьте в документ последнюю измененную временную метку. Загрузите документ, позвольте пользователю изменить его и использовать временную метку в качестве фильтра при обновлении документа, а также обновить метку времени за один шаг. Если он обновляет 0 документов, вы знаете, что он был изменен тем временем, и вы можете попросить пользователя перезагрузить его.

Ответ 5

Используя оператор $position, это можно сделать, начиная с версии 2.5.3.

Он должен использоваться с каждым оператором $. Из документация:

db.collection.update( <query>,
                  { $push: {
                              <field>: {
                                         $each: [ <value1>, <value2>, ... ],
                                         $position: <num>
                              }
                           }
                  }
                )