MongoDB嵌套文档中的嵌套查询

4

我有这些集合

purchaseorder(采购订单)

{
  "_id": "5f0104a8d0c3a06fc9c06625",
  "purchaseItems": [
    {
      "product": "5eff29e9e2708a0ca980762e",
      "quantity": 1
    },
    {
      "product": "5eff29e9e2708a0ca980762e",
      "quantity": 2
    }
  ],
  "totalQuantity": 0,
  "documentDate": {
    "$date": "2020-07-04T16:00:00.000Z"
  }
}

产品

{
  "_id": "5eff29e9e2708a0ca980762e",
  "name": "name",
  "code": "code",
  "cost": "1",
  "srp": "1",
  "minimum": "1",
  "startEffectiveDate": {
    "$date": "2020-07-04T16:00:00.000Z"
  }
}

如何将嵌入式数组文档中的购买物品字段加入到产品集合中。我需要类似这样的东西。
{
  "_id": "5f0104a8d0c3a06fc9c06625",
  "purchaseItems": [
    {
      "product": {
        "_id": "5eff29e9e2708a0ca980762e",
        "name": "product name"
      },
      "quantity": 1
    },
    {
      "product": {
        "_id": "5eff29e9e2708a0ca980762e",
        "name": "product name 2"
      },
      "quantity": 1
    }
  ],
  "totalQuantity": 0,
  "documentDate": {
    "$date": "2020-07-04T16:00:00.000Z"
  }
}

我尝试使用这个聚合方法,但是结果不正确

[{$lookup: {
  from: 'product',
  'let': {
    purchaseItems: '$purchaseItems'
  },
  pipeline: [
    {
      $lookup: {
        from: 'product',
        'let': {
            product: '$product'
          },
        "pipeline": [
           { "$match": { "$expr": { "$eq": [ "$_id", "$$product" ] } } }
         ],
         "as": "product"  
      }
    }
  ],
  as: 'purchaseItems'
} }]

我对MongoDB不是很熟悉,已经考虑回到SQL。


请查看我的答案这里 - Valijon
@Valijon谢谢您的评论,但是否有一种方法可以不使用map/merge/project来保留所有现有的键值? - Ryan Guamos
1个回答

8

不要放弃。我们可以通过以下2个解决方案获得所需的结果:

  1. 标准的$lookup + $project

说明

a. 使用$map可以遍历数组并对其进行转换(添加/保留/删除字段)
b. 使用$filter可以从数组中获取匹配的项
c. 由于$filter返回一个数组,我们需要使用$arrayElemAt运算符获取单个项目或应用$unwind操作


db.purchaseorder.aggregate([
  {
    "$lookup": {
      "from": "product",
      "localField": "purchaseItems.product",
      "foreignField": "_id",
      "as": "product"
    }
  },
  {
    $project: {
      documentDate: 1,
      totalQuantity: 1,
      purchaseItems: {
        $map: {
          input: "$purchaseItems",
          as: "item",
          in: {
            product: {
              $arrayElemAt: [
                {
                  $filter: {
                    input: "$product",
                    as: "prod",
                    cond: {
                      $eq: [
                        "$$prod._id",
                        "$$item.product"
                      ]
                    }
                  }
                },
                0
              ]
            },
            quantity: "$$item.quantity"
          }
        }
      }
    }
  }
])

MongoPlayground | 从产品中删除额外字段

  1. $lookup 的非相关子查询

解释

自 MongoDB v3.6 版本起,$lookup 允许执行非标准查询以连接两个或多个集合:
a. 我们在查找管道中传递了 purchaseItems
b. 通过产品的 _id 值进行匹配
c. 应用 $filter,只获取相关数量值
d. 使用 $unwind 运算符展开数量字段(记住 $filter 返回数组)
e. 使用 $project 阶段将其转换为所需输出


db.purchaseorder.aggregate([
  {
    "$lookup": {
      "from": "product",
      "let": {
        purchaseItems: "$purchaseItems"
      },
      "pipeline": [
        {
          $match: {
            $expr: {
              $in: [
                "$_id",
                "$$purchaseItems.product"
              ]
            }
          }
        },
        {
          $addFields: {
            quantity: {
              $filter: {
                input: "$$purchaseItems",
                as: "purch",
                cond: {
                  $eq: [
                    "$$purch.product",
                    "$_id"
                  ]
                }
              }
            }
          }
        },
        {
          $unwind: "$quantity"
        },
        {
          $project: {
            _id: 0,
            product: {
              _id: "$_id",
              name: "$name"
            },
            quantity: "$quantity.quantity"
          }
        }
      ],
      "as": "purchaseItems"
    }
  }
])

MongoPlayground


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接