Обновление вложенных массивов в mongodb - PullRequest
44 голосов
/ 08 ноября 2010

У меня есть документ в mongodb с 2-уровневым вложенным массивом объектов, который мне нужно обновить, что-то вроде этого:

{
    id: 1,
    items: [
        {
            id: 2,
            blocks: [
                {
                    id: 3
                    txt: 'hello'
                }
            ]
        }
    ] 
}

Если бы был только один массив глубинного уровня, я мог бы использовать позиционный оператор дляобновить объекты в нем, но для второго уровня единственная опция, которую я нашел, - это использовать позиционный оператор с индексом вложенного объекта, например:

db.objects.update({'items.id': 2}, {'$set': {'items.$.blocks.0.txt': 'hi'}})

Этот подход работает, но мне кажется опасным, так как я 'm Создание веб-службы и индексный номер должны исходить от клиента, который может отправить, скажем, 100000 в качестве индекса, и это заставит mongodb создать массив с 100000 индексами с нулевым значением.

Существуют ли другие способы обновления таких вложенныхобъекты, где я могу ссылаться на идентификатор объекта, а не на его позицию, или, возможно, способы проверить, находится ли указанный индекс за пределами границ, прежде чем использовать его в запросе?

Ответы [ 2 ]

27 голосов
/ 09 ноября 2010

Вот большой вопрос, нужно ли вам использовать монго операции «addToSet» и «push»?Если вы действительно планируете изменять только отдельные элементы в массиве, то вам, вероятно, следует построить эти массивы как объекты.

Вот как я бы структурировал это:

{
    id: 1,
    items: 
        { 
          "2" : { "blocks" : { "3" : { txt : 'hello' } } },
          "5" : { "blocks" : { "1" : { txt : 'foo'}, "2" : { txt : 'bar'} } }
        }
}

Это в основном преобразует все вв объекты JSON вместо массивов.Вы теряете возможность использовать $push и $addToSet, но я думаю, что это делает все проще.Например, ваш запрос будет выглядеть так:

db.objects.update({'items.2': {$exists:true} }, {'$set': {'items.2.blocks.0.txt': 'hi'}})

Вы также заметите, что я сбросил "идентификаторы".Когда вы вкладываете подобные вещи, вы обычно можете заменить «ID» простым использованием этого числа в качестве индекса.Понятие «ID» теперь подразумевается.

Эта функция была добавлена ​​в версии 3.6 с выразительными обновлениями .

db.objects.update( {id: 1 }, { $set: { 'items.$[itm].blocks.$[blk].txt': "hi", } }, { multi: false, arrayFilters: [ { 'itm.id': 2 }, { 'blk.id': 3} ] } )

3 голосов
/ 08 мая 2012

Идентификаторы, которые вы используете, являются линейными числами, и они должны быть откуда-то, как дополнительное поле, например, max_idx или что-то подобное.Это означает один поиск идентификатора и затем обновление.UUID / ObjectId можно использовать для идентификаторов, которые гарантируют, что вы также можете использовать Распределенный CRUD.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...