嵌入文档中的 MongoDB 嵌套查找

Rya*_*mos 4 lookup mongodb spring-mongo mongodb-query aggregation-framework

我有这些收藏

采购订单

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

产品

{
  "_id": "5eff29e9e2708a0ca980762e",
  "name": "name",
  "code": "code",
  "cost": "1",
  "srp": "1",
  "minimum": "1",
  "startEffectiveDate": {
    "$date": "2020-07-04T16:00:00.000Z"
  }
}
Run Code Online (Sandbox Code Playgroud)

如何将 buyItems 中的产品字段加入到产品集合中,该购买项目是一个嵌入式数组文档。我需要这样的东西。

{
  "_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"
  }
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用此聚合,但得到了错误的结果

[{$lookup: {
  from: 'product',
  'let': {
    purchaseItems: '$purchaseItems'
  },
  pipeline: [
    {
      $lookup: {
        from: 'product',
        'let': {
            product: '$product'
          },
        "pipeline": [
           { "$match": { "$expr": { "$eq": [ "$_id", "$$product" ] } } }
         ],
         "as": "product"  
      }
    }
  ],
  as: 'purchaseItems'
} }]
Run Code Online (Sandbox Code Playgroud)

对 mongodb 不太熟悉,我已经在考虑回到 SQL。

Val*_*jon 8

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

  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"
          }
        }
      }
    }
  }
])
Run Code Online (Sandbox Code Playgroud)

Mongo游乐场| 从产品中删除额外的字段

  1. 不相关的子查询$lookup

解释

由于 MongoDBv3.6 $lookup允许执行非标准查询来连接 2 个或更多
集合 我们purchaseItems在查找管道内传递
b。按产品_id值进行匹配。
C。应用$filter,我们只得到相关的数量值
d。我们使用运算符$unwind(记住$filter返回一个数组)
e 来展平数量字段。$project我们用stage转换为所需的输出


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"
    }
  }
])
Run Code Online (Sandbox Code Playgroud)

蒙戈游乐场