MongoDB聚合多次操作

MongoDB aggregation multiple operation

我有一个 items collection:

[
   {_id: '1', name: 'A', description: 'Some description 1'}, 
   {_id: '2', name: 'B', description: 'Some description 2'}, 
   {_id: '3', name: 'C', description: 'Some description 3'}, 
   {_id: '4', name: 'D', description: 'Some description 4'}, 
]

我还有一个collectioncItems:

[
    {_id: '1', itemId: '1', items:[ {itemId: '2', qty: 4}, {itemId: '3', qty: 5}  ]},
    {_id: '2', itemId: '4', items:[ {itemId: '2', qty: 1}, {itemId: '3', qty: 1}  ]},
]

我正在尝试使用聚合获取基于 itemId in CItems collection 的项目的详细信息。

cItems.aggregate([
      { $match: { _id: { $eq: categoryId } } },
      { $unwind: "$items" },
      {
        $lookup: {
          from: "items",
          let: {
            itemId: "$items.itemId",
            items: "$items",
          },
          pipeline: [
            { $match: { $expr: { $eq: ["$_id", "$$itemId"] } } },
            {
              $replaceRoot: {
                newRoot: { $mergeObjects: ["$$items", "$$ROOT"] },
              },
            },
            {
              $project: {
                qty: 1,
                name: 1,
                description: 1,
              },
            },
          ],
          as: "items",
        },
      },
      {
        $group: {
          _id: "$_id",
          items: { $push: { $first: "$items" } },
          name: { $first: "$name" },
          description: { $first: "$description" },
        },
      },
    ]);

我得到的结果是:

{
    "_id": "1",
    "items": [
    {
      "qty": 4,
      "_id": "2",
      "name": "A",
      "description": "Some description 2"
    },
    {
      "qty": 5,
      "_id": "3",
      "name": "C",
      "description": "Some description 3"
    }
  ],
    "name": null,
    "description": null
}

问题是它为不在数组中的 itemId 的名称和描述显示空值。

预期输出:

{
    "_id": "1",
    "items": [
    {
      "qty": 4,
      "_id": "2",
      "name": "A",
      "description": "Some description 2"
    },
    {
      "qty": 5,
      "_id": "3",
      "name": "C",
      "description": "Some description 3"
    }
  ],
    "name": 'A',
    "description": "Some description 1"
}

我使用的是最新版本的MongoDB。

您错过了 $lookup 阶段,无法与 items 一起参加父项目 (itemId) [第二阶段]。

要获取父项的名称和描述,您需要 $arrayElemAt 来获取 parentItem [最后阶段] 的第一项。

解决方案 1

db.cItems.aggregate([
  {
    $match: {
      _id: {
        $eq: categoryId
      }
    }
  },
  {
    $lookup: {
      from: "items",
      localField: "itemId",
      foreignField: "_id",
      as: "parentItem"
    }
  },
  {
    "$unwind": "$items"
  },
  {
    $lookup: {
      from: "items",
      let: {
        itemId: "$items.itemId",
        items: "$items"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $eq: [
                "$_id",
                "$$itemId"
              ]
            }
          }
        },
        {
          $replaceRoot: {
            newRoot: {
              $mergeObjects: [
                "$$items",
                "$$ROOT"
              ]
            }
          }
        },
        {
          $project: {
            qty: 1,
            name: 1,
            description: 1
          }
        }
      ],
      as: "items"
    }
  },
  {
    $group: {
      _id: "$_id",
      items: {
        $push: {
          $first: "$items"
        }
      },
      name: {
        $first: {
          "$arrayElemAt": [
            "$parentItem.name",
            0
          ]
        }
      },
      description: {
        $first: {
          "$arrayElemAt": [
            "$parentItem.description",
            0
          ]
        }
      }
    }
  }
])

Sample Mongo Playground (Solution 1)


解决方案 2

db.cItems.aggregate([
  {
    $match: {
      _id: {
        $eq: categoryId
      }
    }
  },
  {
    $lookup: {
      from: "items",
      localField: "itemId",
      foreignField: "_id",
      as: "parentItem"
    }
  },
  {
    $lookup: {
      from: "items",
      let: {
        items: "$items"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $in: [
                "$_id",
                "$$items.itemId"
              ]
            }
          }
        },
        {
          "$replaceRoot": {
            "newRoot": {
              "$mergeObjects": [
                {
                  $arrayElemAt: [
                    "$$items",
                    0
                  ]
                },
                "$$ROOT"
              ]
            }
          }
        }
      ],
      as: "items"
    }
  },
  {
    $project: {
      _id: 1,
      itemId: 1,
      items: 1,
      name: {
        $arrayElemAt: [
          "$parentItem.name",
          0
        ]
      },
      description: {
        $arrayElemAt: [
          "$parentItem.description",
          0
        ]
      }
    }
  }
])

Sample Mongo Playground (Solution 2)