Как обновить 2 определенных элемента в массиве с 2 разными значениями?

У меня есть документ вида:

{ _id:ObjectID, list:Array }

И список содержит элементы формы (которые я буду называть listElement):

{ _id:ObjectID, time:Number }

Я хочу обновить подполе времени двух конкретных элементов списка, каждый со своим собственным значением. У меня есть доступ к обоим _id из listElements.

Что касается этой проблемы: было бы лучше преобразовать список из массива в объект, чьи ключи являются значениями _id? поэтому я бы сделал db.update(( _id:"Идентификатор документа"}, {"list.423rfasf2q3.time":200, "list.fjsdhfksjdh2432.time":100})?

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


person Discipol    schedule 21.08.2013    source источник


Ответы (1)


Вы не можете обновить два документа с двумя разными значениями, вам нужно будет запустить их как два отдельных обновления.

Вы не хотите помещать данные в свои ключевые значения, лучше оставить их как есть. Нет хорошего способа сопоставить значения ключей вне $exists, и даже это не поддерживает подстановочные знаки. Таким образом, вам нужно будет получить ObjectId, преобразовать его в строку, соединить с ключом, а затем запросить документы, в которых этот ключ существует. Гораздо проще просто поместить значение в документ в виде массива. Кроме того, в MongoDB нет возможности индексировать значения ключей, поэтому, если вы хотите индексировать свои данные, вам необходимо иметь их в массиве в качестве элемента данных.

Изменить, чтобы включить пример позиционного соответствия

Сначала вставьте два документа

> db.test.insert( {list: [ {_id: new ObjectId(), time: 1234}, {_id: new ObjectId(), time: 4556} ] } )
>

Продемонстрируйте, что они оба там

> db.test.find()
{ "_id" : ObjectId("5215036749177daf439a2ffe"), "list" : [{ "_id" : ObjectId("5215036749177daf439a2ffc"), "time" : 1234 }, { "_id" :
ObjectId("5215036749177daf439a2ffd"), "time" : 4556 } ] }
>

Покажите, что если мы выполним обычный фильтр массива, мы получим все элементы массива

> db.test.find({"list._id":ObjectId("5215036749177daf439a2ffc")})
{ "_id" : ObjectId("5215036749177daf439a2ffe"), "list" : [ { "_id" : ObjectId("5215036749177daf439a2ffc"), "time" : 1234 }, { "_id" :
ObjectId("5215036749177daf439a2ffd"), "time" : 4556 } ] }
>

Продемонстрируйте, что мы можем использовать оператор $ для возврата только первого совпавшего элемента массива.

> db.test.find({"list._id":ObjectId("5215036749177daf439a2ffc")}, {_id: 0, "list.$": 1})
{ "list" : [ { "_id" : ObjectId("5215036749177daf439a2ffc"), "time" : 1234 } ] }
person Mason    schedule 21.08.2013
comment
Я действительно не хочу делать отдельные запросы, это слишком сильно перегрузит мою систему транзакций. Дальше опять же действия независимы друг от друга, но я должен возвращать клиенту 1 обновление на все операции, поэтому я и хотел стакать вызовы. Почему я не мог индексировать подполя подполей документов? - person Discipol; 21.08.2013
comment
Проблема в том, что нет синтаксиса, чтобы сообщить MongoDB выполнить условное обновление (если _id = x, тогда установите значение y, если _id = a, тогда установите значение b). Обновление документа является относительно легким, будет очень небольшая разница между обновлением двух документов за один вызов или двух документов за два вызова — вы можете подумать о сегментировании, если ваша система не может справиться с объемом. Причина, по которой индексация не будет работать, если вы поместите ObjectId в ключ, заключается в том, что вы должны установить свой индекс для определенного имени ключа. Если вы встраиваете ObjectId в ключ, тогда нет имени ключа для установки вашего индекса. - person Mason; 21.08.2013
comment
что, если я просто проиндексирую подполе списка? поможет ли это только при получении самого подполя списка? все это? - person Discipol; 21.08.2013
comment
Индексирование подполя list поможет только при прямом доступе к list. Есть ли причина, по которой вы так настроены на добавление ObjectId к имени ключа? Это все равно не поможет вам обновить два ключа с двумя разными значениями за одну операцию. - person Mason; 21.08.2013
comment
Мне нужно как-то идентифицировать listElements :| и я постараюсь обращаться к ним по отдельности чаще, чем получать весь список. Я заинтересован в использовании ObjectID, потому что это случайный способ их идентификации. Я не хочу использовать _0, _1.._n в качестве ключей для зданий и их _id. - person Discipol; 21.08.2013
comment
Вы можете использовать оператор позиционного сопоставления в своей проекции, чтобы вернуть только тот элемент массива, который соответствует вашему фильтру. Я обновил свой ответ примером выше. - person Mason; 21.08.2013
comment
Я решил переключиться на хранение listElements в качестве свойств списка, где key представляет собой строку, созданную objectid, чтобы обеспечить уникальность. Хотя я использую свои элементы по отдельности, я все равно получаю их через _id документа и просто обновляю под-под-под-подполя документа. Мне не нужен индекс для этого конкретного случая. - person Discipol; 22.08.2013