mongoose 如何将实体字段添加到已连接的文档中?

vcirk6k6  于 2022-11-13  发布在  Go
关注(0)|答案(1)|浏览(164)

我有一个电子商务服务器,其中有一个products和一个orders集合。
任何product文档都包含唯一的productId,例如prod_123。每个order文档都包含一个lineItems(数组)字段,该字段返回所购买产品的productId以及所购买的相应quantity,例如

[{ productId: 'prod_123', quantity: 2 }, { productId: 'prod_234', quantity: 7 }, ...]

当我的客户获取他们的订单时,我希望用products集合中的匹配产品文档填充每个lineItems元素的productId
我已经编写了一个mongoDB聚合管道来实现这一点,目前为止就是这样:

const orderPipeline = [
    {
      $match: { customerId: 'the customer's ID' },
    },
    {
      $lookup: {
        from: 'products',
        let: { productIds: '$lineItems.productId' },
        pipeline: [
          { $match: { $expr: { $in: ['$productId', '$$productIds'] } } },
          //*** somehow, need to add in corresponding `lineItem.quantity` here
        ],
        as: 'products',
      },
    },
    { $unset: ['lineItems'] },
  ];

但是,正如您所看到的,虽然连接正在进行,但在删除lineItems之前,我无法计算出如何将匹配产品的quantity添加到连接的product中。
如何将对应的quantity添加到对应的匹配product中?

5anewei6

5anewei61#

考虑到评论中提到的额外约束,我 * 非常肯定 * 会起作用的一种方法是利用the $zip operator
1.执行$lookup,使用从其他集合检索到的信息生成数组(products)。
1.使用$addFields阶段作为大部分组合逻辑发生的地方。它将两个数组一起$zip,然后$map$mergeObjects,每个对都变成一个单独的对象。
1.以$unset阶段结束,以删除原始的lineItems字段(该字段已经合并到重新创建的products数组中)。
完整的管道如下所示:

db.orders.aggregate([
  {
    $match: {
      customerId: 123
    },
    
  },
  {
    $lookup: {
      from: "products",
      let: {
        productIds: "$lineItems.productId"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $in: [
                "$productId",
                "$$productIds"
              ]
            }
          }
        }
      ],
      as: "products",
      
    }
  },
  {
    "$addFields": {
      "products": {
        "$map": {
          "input": {
            "$zip": {
              "inputs": [
                "$lineItems",
                "$products"
              ]
            }
          },
          "in": {
            "$mergeObjects": "$$this"
          }
        }
      }
    }
  },
  {
    $unset: "lineItems"
  }
])

Playground example here
乍一看,$map$mergeObjects: "$$this"可能看起来很奇怪。这是必需的,因为$zip将生成一个数组的数组(每个数组有2个条目),如下所示:

"zipped": [
      [
        {
          "productId": "a",
          "quantity": 1
        },
        {
          "_id": ObjectId("5a934e000102030405000002"),
          "productId": "a"
        }
      ],
      [
        {
          "productId": "b",
          "quantity": 2
        },
        {
          "_id": ObjectId("5a934e000102030405000003"),
          "productId": "b"
        }
      ],
      [
        {
          "productId": "c",
          "quantity": 3
        },
        {
          "_id": ObjectId("5a934e000102030405000004"),
          "productId": "c"
        }
      ]
    ]

Here is a playground link,显示压缩后但进一步处理前的输出。)
因此,我们需要将每个对象都折叠成一个对象,因此就有了$mergeObjects。外部数组中的每个对象都是一个数组(包含我们要合并的两个对象),这就是为什么我们可以简单地使用"$$this"作为运算符的输入表达式。

相关问题