Агрегация MongoDB: «Заполнить» (решить) Ссылка на вложенный массив - PullRequest
0 голосов
/ 10 октября 2019

Фон

У меня есть коллекция Items с такими документами, как

{
  "_id": "5d9e3a5ced27230f68032e21",
  ... more fields
  "foos": [
    {
      "_id": "5d9e3a5ced27230f68032e25",
      ... more fields
      "bars": [
        "5d9dab461bbb4db66db41f93"
      ],
    },
    {
      "id": "5d9e3a5ced27230f68032e24",
      ... more fields
      "bars": [
        "5d9dab461bbb4db66db41f93",
        "5d9e3a23ed27230f68032e1a"
      ]
    }
  ]
}

с bars, относящимся к другой коллекции Bars.

Цель

Я хотел бы получить список всех документов (со всеми их полями) в Items, но с разрешением bars в документе в Bars.

Small Catch

Я хочу иметь возможность создать универсальную функцию, которой я просто передаю путь для разрешения (например, foos.bars) и коллекцию для разрешения (Bars)так что я могу использовать его с различными коллекциями и произвольными уровнями вложенности.

Начальный подход

Я нашел довольно сложный способ сделать это для моего примера, но прежде чем обобщить это,Я хотел бы знать, действительно ли нет более простого способа. Вклад очень важен!

Вот что я получил:

[
  {
    "$unwind": {
      "path": "$foos", 
      "includeArrayIndex": "foos_index"
    }
  },
  {
    "$unwind": {
      "path": "$foos.bars"
    }
  },
  {
    "$lookup": {
      "from": "Bars", 
      "localField": "foos.bars", 
      "foreignField": "_id", 
      "as": "foos.bars"
    }
  },
  {
    "$unwind": {
      "path": "$foos.bars"
    }
  },
  {
    "$group": {
      "_id": {
        "id": "$_id", 
        "foo_index": "$foos_index"
      }, 
      "foos": {
        "$first": "$foos"
      }, 
      "bars": {
        "$push": "$foos.bars"
      }
    }
  },
  {
    "$addFields": {
      "foos": {
        "$mergeObjects": [
          "$foos",
          {
            "bars": "$bars"
          }
        ]
      }
    }
  },
  {
    "$group": {
      "_id": "$_id.id", 
      "foos": {
        "$push": "$foos"
      }
    }
  },
  {
    "$lookup": {
      "from": "Items", 
      "localField": "_id", 
      "foreignField": "_id", 
      "as": "original_doc"
    }
  },
  {
    "$unwind": {
      "path": "$original_doc"
    }
  },
  {
    "$replaceRoot": {
      "newRoot": {
        "$mergeObjects": [
          "$original_doc",
          {
            "foos": "$foos"
          }
        ]
      }
    }
  }
]

Обновление: первая итерация

Я понял, что мне не нужен "лист"уровень раскручивался, поэтому у меня теперь есть упрощенная версия (но для более глубокого вложения мне все равно понадобится то, что было раньше, верно?):

[
  {
    "$unwind": {
      "path": "$foos", 
      "includeArrayIndex": "foos_index"
    }
  },
  {
    "$lookup": {
      "from": "Bars", 
      "localField": "foos.bars", 
      "foreignField": "_id", 
      "as": "foos.bars"
    }
  },
  {
    "$group": {
      "_id": "$_id", 
      "foos": {
        "$push": "$foos"
      }
    }
  },
  {
    "$lookup": {
      "from": "Items", 
      "localField": "_id", 
      "foreignField": "_id", 
      "as": "original_doc"
    }
  },
  {
    "$unwind": {
      "path": "$original_doc"
    }
  },
  {
    "$replaceRoot": {
      "newRoot": {
        "$mergeObjects": [
          "$original_doc",
          {
            "foos": "$foos"
          }
        ]
      }
    }
  }
]

1 Ответ

0 голосов
/ 22 октября 2019

Может быть, кто-то все еще находит что-то лучше, но до тех пор, если кто-то сталкивается с этим, мне покажется разумным следующее:

[
  {
    "$unwind": {
      "path": "$foos", 
      "includeArrayIndex": "foos_index"
    }
  },
  {
    "$lookup": {
      "from": "Bars", 
      "localField": "foos.bars", 
      "foreignField": "_id", 
      "as": "foos.bars"
    }
  },
  {
    "$group": {
      "_id": "$_id",
      "savepoint": {
        "$first": "$$ROOT"
      },
      "foos": {
        "$push": "$foos"
      }
    }
  },
  {
    "$replaceRoot": {
      "newRoot": {
        "$mergeObjects": [
          "$savepoint",
          {
            "foos": "$foos"
          }
        ]
      }
    }
  }
]
...