MongoDB Aggregator превращает массив в значения ключей root - PullRequest
1 голос
/ 25 апреля 2020

Моя цель - получить последний обновленный ключ и заново создать объект пользователя с этими обновлениями.

У меня есть следующие данные:

[{"_id":"5ea46dcec84e0bb1aaf510d6","createdAt":{"$numberLong":"1587834215451"}},
{"_id":{"$oid":"5ea46e88c84e0bb1aaf510d7"},"documentId":"5ea46dcec84e0bb1aaf510d6","key":"name","value":"Jim Jenkins","type":"update","createdAt":{"$numberLong":"1587834215451"}},
{"_id":{"$oid":"5ea46e88c84e0bb1aaf510d8"},"documentId":"5ea46dcec84e0bb1aaf510d6","key":"address.line1","value":"5638 Jackson Avenue","createdAt":{"$numberLong":"1587834215451"},"type":"update"},
{"_id":{"$oid":"5ea4711bc84e0bb1aaf510d9"},"documentId":"5ea46dcec84e0bb1aaf510d6","key":"name","value":"Jim Jenkins the third","type":"update","createdAt":{"$numberLong":"1587834213451"}},
{"_id":{"$oid":"5ea47298c84e0bb1aaf510da"},"documentId":"5ea46dcec84e0bb1aaf510d6","key":"name","value":"Bryan Jenkins","type":"update","createdAt":{"$numberLong":"1587835530397"}}]

И конвейер, который выглядит как это:

[{
    $match: {
        type: "update",
        documentId: "5ea46dcec84e0bb1aaf510d6"
    }
}, {
    $sort: {
        "createdAt": -1
    }
}, {
    $group: {
        "_id": {
            "referenceId": "$referenceId",
            "key": "$key"
        },
        "top": {
            "$first": "$$ROOT"
        }
    }
}, {
    $group: {
        "_id": "$top.documentId",
        "key-values": {
            "$push": {
                "k": "$_id.key",
                "v": "$top.value"
            }
        },
        "updatedAt": {
            "$first": "$top.createdAt"
        }
    }
}, {
    $lookup: {
        "from": "users",
        "localField": "_id",
        "foreignField": "_id",
        "as": "reference"
    }
}]

У меня есть следующее key-values в конвейере:

{
    "key-values": [
        { k:"name", v:"Bryan Jenkins" },
        { k:"address.line1", v:"My Address"}
    ]
}

Что я хотел бы получить в итоге:

{
    "_id": "5ea46dcec84e0bb1aaf510d6"
    "name": "Bryan Jenkins",
    "address-line1": "My Address"
    "updatedAt": 1587835530397
}


//Or even better:
{
    "_id": "5ea46dcec84e0bb1aaf510d6"
    "name": "Bryan Jenkins",
    "address": {
        "line1": "My Address"
    },
    "updatedAt": 1587835530397
}

Я не могу на всю жизнь понять, как заменить root, перебирая значения ключей. Я пробовал серию $replaceRoot с $mergeObjects, но не могу этого сделать, потому что ключ в значениях ключей совершенно неизвестен.

У кого-нибудь есть предложения?

1 Ответ

2 голосов
/ 25 апреля 2020

Вы можете заменить ваш второй $group этап на:

  {
    $group: {
      "_id": "$top.documentId",
      "key-values": {
        $mergeObjects: {
          $arrayToObject: [
            [
              {
                "k": "$_id.key",
                "v": "$top.value"
              }
            ]
          ]
        }
      },
      "updatedAt": { "$first": "$top.createdAt" }
    }
  },
  {
    $replaceRoot: {
      newRoot: {
        $mergeObjects: [
          "$key-values",
          {
            _id: "$_id"
          },
          {
            updatedAt: "$updatedAt"
          }
        ]
      }
    }
  }

На всякий случай, если у вас есть больше полей (не только _id & updatedAt) в root документе, который требуется для слияния с key-values затем:

  {
    $group: {
      "_id": "$top.documentId",
      "key-values": {
        $mergeObjects: {
          $arrayToObject: [
            [
              {
                "k": "$_id.key",
                "v": "$top.value"
              }
            ]
          ]
        }
      },
      "updatedAt": { "$first": "$top.createdAt" }
    }
  },
  {
    $replaceRoot: { newRoot: { $mergeObjects: [ "$key-values", "$$ROOT" ] } }
  },
  {
    $project: { "key-values": 0 }
  }

Тест: mongoplayground

Ссылка: агрегация

...