MongoDB $lookup with conditional foreignField

MongoDB $lookup with conditional foreignField

游乐场:https://mongoplayground.net/p/OxMnsCFZpmQ

我的MongoDB版本:4.2.

我有一个集合 car_partscustomers。 顾名思义,car_parts 有汽车零件,其中一些零件可以有一个字段 sub_parts,它是该零件包含的 car_parts._id 的列表。

每位在我们这里购买商品的客户都存储在 customers 中。客户的 parts 字段包含客户在特定日期一起购买的零件列表。

我想在 MongoDB 中进行聚合查询,即 returns 从 customers 购买了哪些汽车零件 (bought_parts) 的映射。但是,如果 car_parts 有字段 sub_parts,客户应该只出现在子部分。

所以 playground 中的查询已经给出了几乎正确的结果,除了 sub_parts 主题。

customer_3 示例:

{
      "_id": "customer_3",
      "parts": [
        {
          "bought_parts": [
            3
          ],
          date: "15.07.2020"
        }
      ]
   }

因为 bought_partscar_parts._id = 3:

{
      "_id": 3,
      "name": "steering wheel",
      "sub_parts": [
        1, // other car_parts._id s
        2
      ]
 }

结果应显示 customer_3 作为汽车部件 1 和 2 的客户。 我不确定如何完成此操作,但我假设用实际 ID [1,2] 来“临时”替换 bought_parts 中的 ID 3 可能会解决问题。

预期输出:

[
  {
    "_id": 1,
    "customers": [
      "customer_1",
      "customer_2",
      "customer_3"  // <- since customer_3 bought car part 3 which has 1 in sub_parts
    ]
  },
  {
    "_id": 2,
    "customers": [
     "customer_3"  // <- since customer_3 bought car part 3 which has 2 in sub_parts
    ]
  },
  {
    "_id": 3,
    "customers": [
      "customer_1", // <- since car_parts.id = 3 has [1, 2] in sub_parts, show customers of ids [1, 2]
      "customer_2",
      "customer_3"
    ]
  },
  {
    "_id": 4,
    "customers": [
      "customer_1",
      "customer_2"
    ]
  }
]

非常感谢!

编辑:一种方法是:

db.car_parts.aggregate([
  {
    $project: {
      topLevel: {$concatArrays: [{$ifNull: ["$sub_parts", []]}, ["$_id"]]},
      sub_parts: 1
    }
  },
  {$unwind: "$topLevel"},
  {
    $group: {
      _id: "$topLevel",
      parts: {$push: "$_id"},
      sub_parts: {$first: "$sub_parts"}
    }
  },
  {
    $project: {
      parts: {$concatArrays: [{"$ifNull": ["$sub_parts", []]}, "$parts"]}
    }
  },
  {
    $lookup: {
      from: "customers",
      localField: "parts",
      foreignField: "parts.scanned_parts",
      as: "customers"
    }
  },
  {$project: {customers: "$customers._id"}}
])

如您所见,正在处理 this playground

既然你说sub-parts只有一层,我就换个思路:在$lookup之前创建一个顶层。例如,由于您希望使用第 3 部分的客户在第 1,2 部分(共 3 个 sub-parts)下注册,因此我们的想法是将它们分组。 $lookup 之后的这种连接有点笨拙,但是如果我们使用 $lookup 之前的 car_parts 集合中的数据,我们实际上已经知道第 1、2 部分是子部分of 3. 创建一个 topLevel 临时字段,允许预先对所有部件和 sub-parts 进行分组,如果客户使用它们,他应该在这个顶级部件下注册。这让事情变得更加优雅......