如何在 MongoDB 聚合管道中执行嵌套“连接”(连接 3 个或更多集合)?

Gre*_*mas 4 mongodb nosql nosql-aggregation aggregation-framework

假设 MongoDB 中有 3 个假设的集合:customersordersorderItems

每个客户有多个订单,每个订单有多个订单项目。

以下是这 3 个集合的一些示例数据:

顾客

[
    {
        customer_id: 1,
        name: "Jim Smith",
        email: "jim.smith@example.com"
    },
    {
        customer_id: 2,
        name: "Bob Jones",
        email: "bob.jones@example.com"
    }
]
Run Code Online (Sandbox Code Playgroud)

命令

[
    {
        order_id: 1,
        customer_id: 1
    },
    {
        order_id: 2,
        customer_id: 1
    }
]
Run Code Online (Sandbox Code Playgroud)

订单项目

[
    {
        order_item_id: 1,
        name: "Foo",
        price: 4.99,
        order_id: 1
    },
    {
        order_item_id: 2,
        name: "Bar",
        price: 17.99,
        order_id: 1
    },
    {
        order_item_id: 3,
        name: "baz",
        price: 24.99,
        order_id: 2
    }
]
Run Code Online (Sandbox Code Playgroud)

期望的结果

如何编写聚合管道以使返回的结果看起来像这样?

[
    {
        customer_id: 1,
        name: "Jim Smith",
        email: "jim.smith@example.com"
        orders: [
            {
                order_id: 1,
                items: [
                    {
                        name: "Foo",
                        price: 4.99
                    },
                    {
                        name: "Bar",
                        price: 17.99
                    }
                ]
            },
            {
                order_id: 2,
                items: [
                    {
                        name: "baz",
                        price: 24.99
                    }
                ]
            }
        ]
    },
    {
        customer_id: 2,
        name: "Bob Jones",
        email: "bob.jones@example.com"
        orders: []
    }
]
Run Code Online (Sandbox Code Playgroud)

tur*_*hal 5

使用带管道的查找进行嵌套查找,

  • $lookuporders收藏,
    • let,定义customer_id来自主集合的变量,以使用$$like访问管道内的此引用变量$$customer_id
    • pipeline可以像我们在根级管道中一样添加管道阶段
    • $expr每当我们匹配内部字段时,它都需要表达式匹配条件,$$customer_id在中声明的父集合字段也是如此let,并且$customer_id是子集合/当前集合的字段
  • $lookuporderitems收藏
db.customers.aggregate([
  {
    $lookup: {
      from: "orders",
      let: { customer_id: "$customer_id" },
      pipeline: [
        { $match: { $expr: { $eq: ["$$customer_id", "$customer_id"] } } },
        {
          $lookup: {
            from: "orderitems",
            localField: "order_id",
            foreignField: "order_id",
            as: "items"
          }
        }
      ],
      as: "orders"
    }
  }
])
Run Code Online (Sandbox Code Playgroud)

操场


提示:

在NoSQL中,有几种连接被认为是不好的做法,我建议您是否可以将订单项添加到订单集合中作为数组,您可以为订单项保存一个连接过程,请参阅playground中的改进版本