收集结构
Order = new Schema
index: { type: Number, unique: true }
number: Date
status: { type: String, enum: ['success', 'failure'] }
created_at: { type: Date, default: Date.now }
updated_at: { type: Date, default: Date.now }
我需要一个查询帮助,该查询返回一个对象数组,其中包含按日期分组的成功计数和失败计数。 前 -
orders = {
28-10-2016:{
success_count: 10,
failure_count: 10
},
29-10-2016: {
success_count: 10,
failure_count: 10
}
}
答案 0 :(得分:4)
使用聚合框架,结果将与您的"期望的"略有不同。输出而不是具有散列键,您将获得一个对象数组,其中_id
键具有一个表示逐个字段的值。例如,而不是
{
"28-10-2016":{
"success_count": 10,
"failure_count": 10
},
"29-10-2016": {
"success_count": 10,
"failure_count": 10
}
}
你有更好的结构,比如
[
{
"_id": "28-10-2016",
"success_count": 10,
"failure_count": 10
},
"_id": "29-10-2016",
"success_count": 10,
"failure_count": 10
}
]
要完成上述结果,需要在 $cond
累加器运算符中使用 $sum
运算符。 $cond
运算符将根据其第一个参数(if)计算逻辑条件,然后返回第二个参数,其中评估为true(然后)或第三个参数,其中false(else) 。这会将true / false逻辑转换为分别输入 $sum
的1和0数值:
"success_count": {
"$sum": {
"$cond": [ { "$eq": [ "$status", "success" ] }, 1, 0 ]
}
}
作为生成的管道,需要运行聚合操作,该操作使用 $dateToString
的_id
键表达式中的 $group
运算符管道:
Orders.aggregate([
{
"$group": {
"_id": {
"$dateToString": {
"format": "%Y-%m-%d",
"date": "$created_at"
}
},
"success_count": {
"$sum": {
"$cond": [ { "$eq": [ "$status", "success" ] }, 1, 0 ]
}
},
"failure_count": {
"$sum": {
"$cond": [ { "$eq": [ "$status", "failure" ] }, 1, 0 ]
}
}
}
}
], function (err, orders){
if (err) throw err;
console.log(orders);
})
但是,有一种更灵活,性能更好的方法,其执行速度比上述方法快得多,其中聚合结果的最有效数据结构遵循模式,例如:
orders = [
{
"_id": "28-10-2016",
"counts": [
{ "status": "success", "count": 10 },
{ "status": "failure", "count": 10 }
]
},
{
"_id": "29-10-2016",
"counts": [
{ "status": "success", "count": 10 },
{ "status": "failure", "count": 10 }
]
}
]
然后考虑运行替代管道,如下所示
Orders.aggregate([
{
"$group": {
"_id": {
"date": {
"$dateToString": {
"format": "%Y-%m-%d",
"date": "$created_at"
}
},
"status": { "$toLower": "$status" }
},
"count": { "$sum": 1 }
}
},
{
"$group": {
"_id": "$_id.date",
"counts": {
"$push": {
"status": "$_id.status",
"count": "$count"
}
}
}
}
], function (err, orders){
if (err) throw err;
console.log(orders);
})