Монго лучшие практики для структурирования массива вложенных документов - PullRequest
0 голосов
/ 18 сентября 2018

Я изо всех сил пытался найти решение следующей проблемы и, похоже, получал противоречивые советы от разных постов mongodb.Я пытаюсь выяснить, как правильно представить «массив» подобъектов таким образом, чтобы:

  1. они могли быть выгружены (т.е. обновлены или новый элемент создан, если необходимо, в одной операции)
  2. идентификаторы объектов доступны в виде значений, которые можно искать, а не только ключей (которые вы не можете реально найти в монго).

У меня есть структура, которую я могупредставить как массив (repr A):

{
    _id: 1,
    subdocs: [
        { sd_id: 1, title: t1 },
        { sd_id: 2, title: t2 },
        ...
    ]
}

или как вложенный документ (repr B)

{
    _id: 1,
    subdocs: {
        1: { title: t1 },
        2: { title: t2 },
        ...
    }
}

Я хотел бы иметь возможность обновить ИЛИ вставить (т.е. upsert)новые поддокеты без необходимости использования дополнительной логики в приложении.

В отчете B это просто, так как я могу просто использовать set

$set: {subdocs.3.title: t3}

в обновлении с upsert: true.

В отчете A возможно обновление существующей записи с использованием 'arrayFilter' с чем-то вроде:

update({_id: 1}, {$set: {subdocs.$[i].title: t3}}, {arrayFilter: [{i.sd_id: 3}], upsert: true})

Проблема заключается в том, что, хотя вышеприведенное обновит существующий подобъект, он не создастновый подобъект (то есть с _id: 3), если он не существует (это не upsert).Документы утверждают, что $ [] поддерживает upsert, но это не работает для меня.

Хотя repr B разрешает обновление / upserts, нет способа искать идентификаторы вложенных документов, потому что они теперь являются ключамиа не ценности.

Единственное решение вышеизложенного состоит в использовании денормализованного представления, например, с идентификатором, сохраняемым как ключ и значение:

subdocs: {
    1: { sd_id: 1, title: t1 },
    2: { sd_id: 2, title: t2 },
    ...
}

Но это кажется ненадежным (поскольку значения могутиз синхронизации).

Так что мой вопрос, есть ли способ обойти это?Возможно, мне не хватает способа сделать upsert в случае A?

ОБНОВЛЕНИЕ: я нашел обходной путь, который позволяет мне эффективно использовать repr A, хотя я не уверен, что он оптимален.Он включает в себя две записи, а не одну:

update({_id: 1, "subdocs.sd_id": {$ne: 3}}, {$push: {subdocs: {sd_id: 3}}})
update({_id: 1}, {$set: {subdocs.$[i].title: t3}}, {arrayFilter: [{i.sd_id: 3}]})

Первая строка в приведенном выше примере гарантирует, что мы когда-либо вставим только один поддок с sd_id 3 (и действует только в том случае, если идентификатор не существует), покавторая строка обновляет запись (которая теперь обязательно должна существовать).Я, вероятно, могу поместить их в упорядоченный пакет, чтобы все это заработало.

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