Использование MergeObjects без перезаписи вложенных документов - PullRequest
1 голос
/ 07 мая 2020

Я пытаюсь объединить два поля в конвейере агрегации.

Я хочу преобразовать это:

{
   "a": 1,
   "b": {
      "first": {
          "property_a": "some_value",
          "property_b": "some_value",
          "property_c": "some_value"
      },
      "second": {
          "property_a": "some_value",
          "property_b": "some_value",
          "property_c": "some_value"
      },
      "third": {
          "property_a": "some_value",
          "property_b": "some_value",
          "property_c": "some_value"
      },
      "fiftieth": {
          "property_a": "some_value",
          "property_b": "some_value",
          "property_c": "some_value"
      }
   },
   "c": {
      "first": {
          "property_x": "some_value",
          "property_y": "some_value"
      },
      "second": {
          "property_x": "some_value",
          "property_y": "some_value"
      },
      "fiftieth": {
          "property_x": "some_value",
          "property_y": "some_value"
      }
   }
}

В это, без необходимости указывать каждый ключ, указанный в «b»:

{
   "a": 1,
   "b": {
      "first": {
          "property_a": "some_value",
          "property_b": "some_value",
          "property_c": "some_value",
          "property_x": "some_value",
          "property_y": "some_value"
      },
      "second": {
          "property_a": "some_value",
          "property_b": "some_value",
          "property_c": "some_value",
          "property_x": "some_value",
          "property_y": "some_value"
      },
      "third": {
          "property_a": "some_value",
          "property_b": "some_value",
          "property_c": "some_value"
      },
      "fiftieth": {
          "property_a": "some_value",
          "property_b": "some_value",
          "property_c": "some_value",
          "property_x": "some_value",
          "property_y": "some_value"
      }
   }
}

В документации для mergeObjects, в нем говорится:

mergeObjects перезаписывает значения полей при слиянии документов. Если документы для слияния содержат одно и то же имя поля, поле в итоговом документе будет иметь значение из последнего документа, объединенного для поля.

Как я могу объединить поддокументы полей b и c без указания каждого ключа (в моем реальном сценарии использования 85 ключей). Кроме того, в поле c могут быть не все ключи, перечисленные в пункте b. Или это невозможно?

1 Ответ

1 голос
/ 08 мая 2020

Вы можете использовать $objectToArray для преобразования объектов в пары k, v, объединения и $unwind их, $group по имени ключа и слияния документов, затем $group по _id для сбора ключей обратно вместе.

db.collection.aggregate([
  {$addFields: {
      combined: {
        $concatArrays: [
          {$objectToArray: "$b"},
          {$objectToArray: "$c"}
        ]
      }
  }},
  {$unwind: "$combined"},
  {$group: {
      _id: {_id: "$_id", key: "$combined.k"},
      doc: {$first: "$$ROOT"},
      v: {$mergeObjects: "$combined.v"}
  }},
  {$group: {
      _id: "$_id._id",
      doc: {$first: "$doc"},
      combined: {$push: {
          k: "$_id.key",
          v: "$v"
      }}
  }},
  {$addFields: {"doc.b": {$arrayToObject: "$combined"}}},
  {$project: {
    combined: 0,
    "doc.c": 0
  }},
  {$replaceRoot: {newRoot: "$doc"}}
])

Детская площадка

...