用于查找和合并嵌套文档的聚合管道

Aggregation pipeline to lookup and merge nested documents

我正在努力编写一个聚合管道以通过它们的 _id 和 return 特定名称查找嵌套文档,而不会覆盖数据中现有的 keys/values。我已经设法为嵌套数组执行此操作,但无法为嵌套在嵌套数组中的数组执行此操作。

所以我想查找每种成分和每个子成分的 _id,并将它们与这些已经存在的成分(即数量、度量)的数据合并。

这是我目前的情况: https://mongoplayground.net/p/ft4oIMm_8wg

产品合集:

[
    {
      "_id": {
        "$oid": "5ecf269bceb735416db0b329"
      },
      "id": 36,
      "title": "Product 1",
      "description": {
        "generalInformation": "Some information",
        "activeIngredients": [
          {
            "_id": 1636,
            "qty": 133.5,
            "measure": "µg",
            "subIngredient": [
              {
                "_id": 1626,
                "qty": 16.6,
                "measure": "µg"
              }
            ],
            
          },
          {
            "_id": 1234,
            "qty": 133.5,
            "measure": "µg",
            "subIngredient": [
              {
                "_id": 1122,
                "qty": 16.6,
                "measure": "µg"
              },
              {
                "_id": 1212,
                "qty": 16.6,
                "measure": "µg"
              }
            ],
            
          },
          
        ]
      },
      
    },
    {
      "_id": {
        "$oid": "5ecf269bceb735416db0b346"
      },
      "id": 36,
      "title": "Product 2",
      "description": {
        "generalInformation": "Some information",
        "activeIngredients": [
          {
            "_id": 1234,
            "qty": 133.5,
            "measure": "µg",
            "subIngredient": [
              {
                "_id": 1122,
                "qty": 16.6,
                "measure": "µg"
              }
            ],
            
          },
          {
            "_id": 1234,
            "qty": 133.5,
            "measure": "µg",
            "subIngredient": [
              {
                "_id": 1122,
                "qty": 16.6,
                "measure": "µg"
              },
              {
                "_id": 1212,
                "qty": 16.6,
                "measure": "µg"
              }
            ],
            
          },
          
        ]
      },
      
    }
  ]

成分收集:

[
    {
      "_id": 1234,
      "name": "Ingredient 1",
      
    },
    {
      "_id": 1122,
      "name": "Ingredient 2",
      
    },
    {
      "_id": 1212,
      "name": "Ingredient 3",
      
    },
    {
      "_id": 1636,
      "name": "Ingredient 4",
      
    },
    {
      "_id": 1626,
      "name": "Ingredient 5",
      
    }
  ]

应该 return编辑什么:

[
  {
    "_id": ObjectId("5ecf269bceb735416db0b329"),
    "title": "Product 1"
    "description": {
      "activeIngredients": {
        "_id": 1636,
        "measure": "µg",
        "name": "Ingredient 4",
        "qty": 133.5,
        "subIngredient": [
          {
            "_id": 1626,
            "measure": "µg",
            "qty": 16.6
          }
        ]
      },
      "generalInformation": "Some information"
    },
    "ingredients": [
      {
        "_id": 1636,
        "measure": "µg",
        "name": "Ingredient 4",
        "qty": 133.5,
        "subIngredient": [
          {
            "_id": 1626,
            "measure": "µg",
            "qty": 16.6,
            "name": "Ingredient 2"
          }
        ]
      },
      {
        "_id": 1234,
        "measure": "µg",
        "name": "Ingredient 1",
        "qty": 133.5,
        "subIngredient": [
          {
            "_id": 1122,
            "measure": "µg",
            "qty": 16.6,
            "name": "Ingredient 2"
          },
          {
            "_id": 1212,
            "measure": "µg",
            "qty": 16.6,
            "name": "Ingredient 2"
          }
        ]
      }
    ]
    
  },
  
]

我当前的管道:

[
  {
    "$unwind": {
      "path": "$description.activeIngredients",
      "preserveNullAndEmptyArrays": false
    }
  },
  {
    "$lookup": {
      "from": "ingredients",
      "localField": "description.activeIngredients._id",
      "foreignField": "_id",
      "as": "description.activeIngredients.name"
    }
  },
  {
    "$addFields": {
      "description.activeIngredients.name": {
        "$arrayElemAt": [
          "$description.activeIngredients.name.name",
          0
        ]
      }
    }
  },
  {
    "$group": {
      "_id": "$_id",
      "ingredients": {
        "$push": "$description.activeIngredients"
      },
      "description": {
        "$first": "$description"
      },
      "title": {
        "$first": "$title"
      }
    }
  },
  {
    "$lookup": {
      "from": "ingredients",
      "localField": "ingredients.subIngredient._id",
      "foreignField": "_id",
      "as": "subIngredients"
    }
  }
]

感谢任何帮助。谢谢。

你离得不远了,你可以通过多种不同的方式实现这个结果,其中之一就是 $unwind subingredients 数组,$lookup 然后最后添加另一个 $group 阶段来重组文档。

正如你清楚地表明你知道如何做所有这些事情,我将展示一种不同的方式来利用像 $map, $indexOfArray and Mongo's v3.6 $lookup 语法这样的运算符。

我们的策略不是展开子数组,而是 $lookup 所有相关 sub-ingredients,然后使用我指定的运算符“合并”两个数组。

即服用:

[ {id: 5, name: "name"} ];
[ {id: 5, qty: 25} ]

并将它们制作成:

[ {id: 5, name: "name", qty: 25} ]

我们是这样做的:

db.products.aggregate([
  {
    "$unwind": {
      "path": "$description.activeIngredients",
      "preserveNullAndEmptyArrays": false
    }
  },
  {
    "$lookup": {
      "from": "ingredients",
      "localField": "description.activeIngredients._id",
      "foreignField": "_id",
      "as": "description.activeIngredients.name"
    }
  },
  {
    "$addFields": {
      "description.activeIngredients.name": {
        "$arrayElemAt": [
          "$description.activeIngredients.name.name",
          0
        ]
      }
    }
  },
  {
    "$lookup": {
      "from": "ingredients",
      "let": {
        sub: "$description.activeIngredients.subIngredient"
      },
      "pipeline": [
        {
          $match: {
            $expr: {
              "$setIsSubset": [
                [
                  "$_id"
                ],
                {
                  $map: {
                    input: "$$sub",
                    as: "datum",
                    in: "$$datum._id"
                  }
                }
              ]
            }
          }
        }
      ],
      "as": "subIngredients"
    }
  },
  {
    "$addFields": {
      "description.activeIngredients.subIngredient": {
        $map: {
          input: "$description.activeIngredients.subIngredient",
          as: "sub",
          in: {
            "$mergeObjects": [
              "$$sub",
              {
                name: {
                  $arrayElemAt: [
                    "$subIngredients.name",
                    {
                      "$indexOfArray": [
                        "$subIngredients._id",
                        "$$sub._id"
                      ]
                    }
                  ]
                }
              }
            ]
          }
        }
      }
    }
  },
  {
    "$group": {
      "_id": "$_id",
      "ingredients": {
        "$push": "$description.activeIngredients"
      },
      "description": {
        "$first": "$description"
      },
      "title": {
        "$first": "$title"
      }
    }
  }
])

MongoPlayground