如何按 MongoDB 中的特定字段对文档进行分组

How to group documents by a specific field in MongoDB

目前,我有一个集合 book_orders,如下所示:

{
    "order_id" : 1,
    "customer_name": "Nikos",
    "order_type": "digital",
    "title": "Zorba",
    "price": 25
}
{
    "order_id" : 2,
    "customer_id": "Giorgos",
    "order_type": "physical_delivery",
    "title": "War and Peace",
    "price": 30
}
{
    "order_id" : 2,
    "customer_id": "Giorgos",
    "order_type": "digital",
    "title": "Children of the Gabalawi Street",
    "price": 35
}
{
    "order_id" : 3,
    "customer_id": "Giorgos",
    "order_type": "digital",
    "title": "The Desert of the Tartars",
    "price": 40
}

我想对这个集合做的是我想要这样的输出,我按 order_id 对订单进行分组,并将它们嵌入名为 digital_orders 和 [=15 的列表中=] 通过 order_type.

的后续分组

我假设我需要使用聚合,但我不确定如何去做。我可以保留 customer_nametitleprice 等字段,这一点很重要。任何帮助表示赞赏。

{
  "order_id": 1,
  "customer_name": "Nikos",
  "digital_orders": [
    {
      "title": "Zorba",
      "price": 25
    }
  ],
  "physical_orders": []
},
{
  "order_id": 2,
  "customer_name": "Giorgos",
  "digital_orders": [
    {
      "title": "War and Peace",
      "total": 25
    }
  ],
  "physical_orders": [
    {
      "title": "Children of the Gabalawi Street",
      "price": 35
    }
  ]
},
{
  "order_id": 3,
  "customer_name": "Giorgos",
  "digital_orders": [],
  "physical_orders": [
    {
      "title": "The Desert of the Tartars",
      "total": 40
    }
  ]
}

你可以试试,

  • $group by order_id 并获得第一个 customer_name 并获得数组中包含必填字段的所有订单
  • $project 显示必填字段,使 2 个字段第一个 digital_orders 从订单数组中过滤数字订单,第二个 physical_orders 从订单数组中过滤物理订单
db.collection.aggregate([
  {
    $group: {
      _id: "$order_id",
      customer_name: { $first: "$customer_name" },
      orders: {
        $push: {
          title: "$title",
          price: "$price",
          order_type: "$order_type"
        }
      }
    }
  },
  {
    $project: {
      _id: 0,
      order_id: "$_id",
      customer_name: 1,
      digital_orders: {
        $filter: {
          input: "$orders",
          cond: { $eq: ["$$this.order_type", "digital"] }
        }
      },
      physical_orders: {
        $filter: {
          input: "$orders",
          cond: { $eq: ["$$this.order_type", "physical_delivery"] }
        }
      }
    }
  }
])

Playground