MongoDB聚合:嵌套数组中的“填充”(解析)引用

时间:2019-10-09 21:32:01

标签: mongodb aggregation-framework

背景

我有一个收藏集Items,其中包含诸如

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

,其中bars引用了另一个集合Bars

目标

我想在Items中获得所有文档的列表(及其所有字段),但是将bars解析为Bars中的文档。

小渔获

我希望能够创建一个通用函数,只需向其传递解析路径(例如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 :(得分:0)

也许有人仍然发现更好的东西,但是直到那时,如果有人遇到了这个问题,那么现在对我来说,以下几点似乎是合理的:

[
  {
    "$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"
          }
        ]
      }
    }
  }
]