mongodb汇总订单按日期分组,列出产品和数量

时间:2017-02-26 19:02:36

标签: mongodb aggregation-framework

我几天来一直在解决这个问题。我有以下订单架构:

order_no: Number,
timestamp: { type: Date, default: Date.now },
total: Number,
details: [
    item:   String,
    price:  Number,
    qty:    Number,
    amt:    Number
]

Orders集合的示例:

[ {
    "order_no": 1,
    "details": [
        {
            "item": "Product A",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58af49c63107ebf7cda2e5fb"
        }
    ],
    "timestamp": "2017-02-23T20:44:54.171Z"
},
{
    "order_no": 2,
    "total": 95,
    "details": [
        {
            "item": "Product B",
            "amt": 95,
            "qty": 1,
            "price": 95,
            "_id": "58af4a618fbad6f7fca6f9c3"
        }
    ],
    "timestamp": "2017-02-23T20:47:29.016Z"
},
{
    "order_no": 3,
    "total": 455,
    "details": [
        {
            "item": "Product A",
            "amt": 180,
            "qty": 2,
            "price": 90,
            "_id": "58af4a818fbad6f7fca6f9ca"
        },
        {
            "item": "Product C",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58af4a818fbad6f7fca6f9c9"
        },
        {
            "item": "Product B",
            "qty": 1,
            "price": 95,
            "amt": 95,
            "_id": "58af4a818fbad6f7fca6f9c8"
        },
        {
            "item": "Product D",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58af4a818fbad6f7fca6f9c7"
        }
    ],
    "timestamp": "2017-02-23T20:48:01.157Z"
},
{
    "order_no": 4,
    "total": 190,
    "details": [
        {
            "item": "Product B",
            "amt": 190,
            "qty": 2,
            "price": 95,
            "_id": "58afd1b7ef77dbfdce1fdb65"
        }
    ],
    "timestamp": "2017-02-24T06:24:55.121Z"
},
{
    "order_no": 5,
    "total": 190,
    "details": [
        {
            "item": "Product B",
            "qty": 2,
            "price": 95,
            "amt": 190,
            "_id": "58afd26b1d7b73fe06cb7d30"
        }
    ],
    "timestamp": "2017-02-24T06:27:55.452Z"
},
{
    "order_no": 6,
    "total": 95,
    "details": [
        {
            "item": "Product B",
            "qty": 1,
            "price": 95,
            "amt": 95,
            "_id": "58afd2de230c85fe34af8018"
        }
    ],
    "timestamp": "2017-02-24T06:29:50.115Z"
},
{
    "order_no": 7,
    "total": 95,
    "details": [
        {
            "item": "Product B",
            "qty": 1,
            "price": 95,
            "amt": 95,
            "_id": "58afd30cd123befe49cfe30d"
        }
    ],
    "timestamp": "2017-02-24T06:30:36.947Z"
},
{
    "order_no": 8,
    "total": 95,
    "details": [
        {
            "item": "Product B",
            "qty": 1,
            "price": 95,
            "amt": 95,
            "_id": "58afd372fed156fe67ff00a9"
        }
    ],
    "timestamp": "2017-02-24T06:32:18.219Z"
},
{
    "order_no": 9,
    "total": 95,
    "details": [
        {
            "item": "Product B",
            "qty": 1,
            "price": 95,
            "amt": 95,
            "_id": "58afd3c4a64da9fe849e3281"
        }
    ],
    "timestamp": "2017-02-24T06:33:40.555Z"
},
{
    "order_no": 10,
    "total": 540,
    "details": [
        {
            "item": "Product A",
            "price": 90,
            "amt": 540,
            "qty": 6,
            "_id": "58afd3d2a64da9fe849e3283"
        }
    ],
    "timestamp": "2017-02-24T06:33:54.184Z"
},
{
    "order_no": 11,
    "total": 540,
    "details": [
        {
            "item": "Product C",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58afef53a64da9fe849e328a"
        },
        {
            "item": "Product E",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58afef53a64da9fe849e3289"
        },
        {
            "item": "Product F",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58afef53a64da9fe849e3288"
        },
        {
            "item": "Product A",
            "price": 90,
            "amt": 270,
            "qty": 2,
            "_id": "58afef53a64da9fe849e3287"
        }
    ],
    "timestamp": "2017-02-24T08:31:15.154Z"
},
{
    "order_no": 12,
    "total": 90,
    "details": [
        {
            "item": "Product A",
            "price": 90,
            "amt": 90,
            "qty": 1,
            "_id": "58b000daa64da9fe849e328c"
        }
    ],
    "timestamp": "2017-02-24T09:46:02.968Z"
},
{
    "order_no": 13,
    "total": 90,
    "details": [
        {
            "item": "Product D",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58b000e7a64da9fe849e328e"
        }
    ],
    "timestamp": "2017-02-24T09:46:15.359Z"
},
{
    "order_no": 14,
    "total": 235,
    "details": [
        {
            "item": "Product E",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58b000eea64da9fe849e3293"
        },
        {
            "item": "Product F",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58b000eea64da9fe849e3292"
        },
        {
            "item": "Product G",
            "amt": 55,
            "qty": 1,
            "price": 55,
            "_id": "58b000eea64da9fe849e3291"
        }
    ],
    "timestamp": "2017-02-24T09:46:22.047Z"
},
{
    "order_no": 1,
    "total": 275,
    "details": [
        {
            "item": "Product A",
            "price": 90,
            "amt": 180,
            "qty": 2,
            "_id": "58b1e56dcf91ba1d8886ea30"
        },
        {
            "item": "Product B",
            "amt": 95,
            "qty": 1,
            "price": 95,
            "_id": "58b1e56dcf91ba1d8886ea2f"
        }
    ],
    "timestamp": "2017-02-25T20:13:33.190Z"
},
{
    "order_no": 2,
    "total": 180,
    "details": [
        {
            "item": "Product E",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58b1e578cf91ba1d8886ea35"
        },
        {
            "item": "Product F",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58b1e578cf91ba1d8886ea34"
        }
    ],
    "timestamp": "2017-02-25T20:13:44.254Z"
},
{
    "order_no": 3,
    "total": 235,
    "details": [
        {
            "item": "Product D",
            "amt": 90,
            "qty": 1,
            "price": 90,
            "_id": "58b1e58ecf91ba1d8886ea3d"
        },
        {
            "item": "Product G",
            "amt": 55,
            "qty": 1,
            "price": 55,
            "_id": "58b1e58ecf91ba1d8886ea3c"
        },
        {
            "item": "Product E",
            "qty": 1,
            "price": 90,
            "amt": 90,
            "_id": "58b1e58ecf91ba1d8886ea3b"
        }
    ],
    "timestamp": "2017-02-25T20:14:06.161Z"
}]

我如何进行聚合输出以下内容:

{
    "_id": {
        "day": 24, "month": 2, "year": 2017
    },
    "products": [
        item: "Product A", totalqty: 3, totalamt: 270,
        item: "Product B", totalqty: 2, totalamt: 180,
        item: "Product C", totalqty: 1, totalamt: 90,
        item: "Product D", totalqty: 5, totalamt: 450,
    ]
},
{
    "_id": {
        "day": 25, "month": 2, "year": 2017
    },
    "products": [
        item: "Product A", totalqty: 1, totalamt: 90,
        item: "Product B", totalqty: 2, totalamt: 180,
        item: "Product C", totalqty: 3, totalamt: 270,
    ]
}, etc, etc

请帮助我找一下如何对每个日期进行分组,并列出每种产品的总数量和总量。

2 个答案:

答案 0 :(得分:3)

您可以尝试以下聚合。

$unwind详细信息,首先$group timestampitem,然后按$group计算总数量和金额以及最终timestamp将具有先前计算的数量和金额值的项目推送到products

db.orders.aggregate({
    $unwind: "$details"
}, {
    $group: {
        _id: {
            month: {$month: "$timestamp"},
            day: {$dayOfMonth: "$timestamp"},
            year: {$year: "$timestamp"},
            item: "$details.item"
        },
        totalqty: {$sum: "$details.qty"},
        totalamt: {$sum: "$details.amt"}
    }
}, {
    $group: {
        _id: {
            month: "$_id.month",
            day: "$_id.day",
            year: "$_id.year"
        },
        products: {
            $push: {
                item: "$_id.item",
                totalqty: "$totalqty",
                totalamt: "$totalamt"
            }
        }
    }
})

答案 1 :(得分:1)

如果你正在使用mongoose,这就是整体解决方案:

然后您可以按照@ Veeram的解决方案,首先需要unwind details数组将每个细节项目转换为新文档。然后,您可以按产品ID和日期对文档进行分组(此处我们使用聚合框架&#date}帮助函数,例如$month$dayOfMonth$year)。最后,如果您需要将一天的所有产品放在一个数组下,您可以groupBy天。您可以通过官方文档详细了解groupBy如何合作:https://docs.mongodb.com/manual/reference/operator/aggregation/group/

const Promise = require("bluebird");
const mongoose = require("mongoose");
mongoose.connect('mongodb://localhost/myapp');
const schema = {
  order_no: Number,
  timestamp: {type: Date, default: Date.now},
  total: Number,
  details: [{
    item: String,
    price: Number,
    qty: Number,
    amt: Number
  }]
};

const ordersSchema = new mongoose.Schema(schema, {collection: "orders"});
const ordersCollection = mongoose.model("Orders", ordersSchema);


const aggregations = [];
aggregations.push({$unwind: "$details"});
aggregations.push({
  $group: {
    _id: {
      month: {$month: "$timestamp"},
      day: {$dayOfMonth: "$timestamp"},
      year: {$year: "$timestamp"},
      productId: "$details.item"
    },
    totalQuantity: {$sum: "$details.qty"},
    totalAmount: {$sum: "$details.amt"}
  }
});
aggregations.push({
  $group: {
    _id: {month: "$_id.month", day: "$_id.day", year: "$_id.year"},
    productSummaries: {
      $push: {
        item: "$_id.productId",
        totalQuantity: "$totalqty",
        totalAmount: "$totalamt"
      }
    }
  }
});

ordersCollection.aggregate(aggregations).then(results => results.forEach(result => console.log(result))).catch(err => console.error(err));