MongoDB 聚合总和增长
MongoDB Aggregation Sum Growth
我有一个 MondoDB 聚合管道,它通过聚合所有 Sales
:
输出每日收入金额
Sale.aggregate
([
{
$project: {
day: { $substr: ['$createdAt', 0, 10], },
},
},
{
$group: {
_id: '$day',
earnings: { $sum: '$pricing.earnings' },
},
},
{
$sort: {
_id: 1
}
},
{
$project: {
date: '$_id',
earnings: '$earnings',
},
},
{
$group: {
_id: null,
stats: { $push: '$$ROOT' },
}
},
{
$project: {
stats: {
$map: {
// returns an array with all dates between 2 provided params
input: dates.daysArray(dates.getDay(user.createdAt), dates.today()),
as: 'date',
in: {
$let: {
vars: { index: { $indexOfArray: ['$stats._id', '$$date'] } },
in: {
$cond: {
if: { $ne: ['$$index', -1] },
then: { $arrayElemAt: ['$stats', '$$index'] },
else: { _id: '$$date', date: '$$date', earnings: 0 }
}
}
}
}
}
}
}
},
{
$unwind: '$stats'
},
{
$replaceRoot: {
newRoot: '$stats'
}
},
{
$project: {
_id: 0,
x: '$date',
y: '$earnings',
},
},
])
此管道的输出可能如下所示:
[
{
x: '2019-01-09',
y: 10,
},
{
x: '2019-01-10',
y: 5,
},
{
x: '2019-01-11',
y: 20,
}
]
这意味着在 2019-01-09
有销售额为 10 美元,在 2019-01-10
有 5 美元,等等
现在,我想要的不是每日收入,而是所有收入的总和。
这意味着结果应该如下所示:
[
{
x: '2019-01-09',
y: 10, // a total of on the first day
},
{
x: '2019-01-10',
y: 15, // a total of on the second day (10 + 5)
},
{
x: '2019-01-11',
y: 35, // a total of on the third day (15 + 20)
}
]
所以基本上我不想要每天的数量而是增长。
P.S.: 我正在使用此数据显示在图表中。
聚合框架独立处理所有文档(按设计),因此它们彼此不了解。改变它的唯一方法是使用 $group. Setting _id
to null
allows you to capture the data from all documents into single one. Then you can iterate through that arrays (using $range to get the array of indexes and $map to return another array). It's easy to get x
($arrayElemAt) and for y
you need to sum all array elements using $reduce. The input for $reduce
is generated by $slice operator and depends on an index (for 0
it will be [10]
, for 1
[10,5]
and so on). To finalize the query you need $unwind and $replaceRoot 获取原始文档形状。
db.col.aggregate([
{
$sort: { x: 1 }
},
{
$group: {
_id: null,
xArr: { $push: "$x" },
yArr: { $push: "$y" }
}
},
{
$project: {
data: {
$map: {
input: { $range: [ 0, { $size: "$xArr" } ] },
as: "i",
in: {
x: { $arrayElemAt: [ "$xArr", "$$i" ] },
y: {
$reduce: {
input: { $slice: [ "$yArr", { $add: [ "$$i", 1 ] } ] },
initialValue: 0,
in: { $add: [ "$$this", "$$value" ] }
}
}
}
}
}
}
},
{
$unwind: "$data"
},
{
$replaceRoot: {
newRoot: "$data"
}
}
])
我想您需要将上述步骤附加到现有聚合中。为了证明它有效,您可以 运行 将其单独收集:
db.col.save({ x: '2019-01-09', y: 10 })
db.col.save({ x: '2019-01-10', y: 5 })
db.col.save({ x: '2019-01-11', y: 20 })
它输出:
{ "x" : "2019-01-09", "y" : 10 }
{ "x" : "2019-01-10", "y" : 15 }
{ "x" : "2019-01-11", "y" : 35 }
您可以在已有的基础上添加以下阶段
逻辑是 $push
x 和 y 到数组,使用 $range
按索引迭代数组,对于 x get $arrayElemAt
at index
,对于 y $slice
和 $sum
直到 index+1
db.t51.aggregate([
{$group : {_id : null, x : {$push : "$x"}, y : {$push : "$y"}}},
{$project : {data : {
$map : {
input : {$range : [0, {$size : "$x"}]},
as : "idx",
in : { x : {$arrayElemAt : ["$x", "$$idx"]}, y : {$sum : {$slice : ["$y", {$sum : ["$$idx",1]}]}}}}
}}},
{$unwind : "$data"},
{$replaceRoot: {newRoot : "$data"}}
]).pretty()
如果您有更多字段需要汇总或预测,您可以使用以下阶段
db.t51.aggregate([
{$group : {_id : null, data : {$push : "$$ROOT"}}},
{$addFields : {data :
{$reduce : {
input : "$data",
initialValue : [{y : 0}],
in : {$concatArrays : [ "$$value",[{$mergeObjects : ["$$this", { y : {$sum : ["$$this.y",{$arrayElemAt : ["$$value.y", -1]}]}}]}]]}
}}
}},
{$addFields : {data : {$slice : ["$data", 1, {$size : "$data"}]}}},
{$unwind : "$data"},
{$replaceRoot: {newRoot : "$data"}}
]).pretty()
我有一个 MondoDB 聚合管道,它通过聚合所有 Sales
:
Sale.aggregate
([
{
$project: {
day: { $substr: ['$createdAt', 0, 10], },
},
},
{
$group: {
_id: '$day',
earnings: { $sum: '$pricing.earnings' },
},
},
{
$sort: {
_id: 1
}
},
{
$project: {
date: '$_id',
earnings: '$earnings',
},
},
{
$group: {
_id: null,
stats: { $push: '$$ROOT' },
}
},
{
$project: {
stats: {
$map: {
// returns an array with all dates between 2 provided params
input: dates.daysArray(dates.getDay(user.createdAt), dates.today()),
as: 'date',
in: {
$let: {
vars: { index: { $indexOfArray: ['$stats._id', '$$date'] } },
in: {
$cond: {
if: { $ne: ['$$index', -1] },
then: { $arrayElemAt: ['$stats', '$$index'] },
else: { _id: '$$date', date: '$$date', earnings: 0 }
}
}
}
}
}
}
}
},
{
$unwind: '$stats'
},
{
$replaceRoot: {
newRoot: '$stats'
}
},
{
$project: {
_id: 0,
x: '$date',
y: '$earnings',
},
},
])
此管道的输出可能如下所示:
[
{
x: '2019-01-09',
y: 10,
},
{
x: '2019-01-10',
y: 5,
},
{
x: '2019-01-11',
y: 20,
}
]
这意味着在 2019-01-09
有销售额为 10 美元,在 2019-01-10
有 5 美元,等等
现在,我想要的不是每日收入,而是所有收入的总和。 这意味着结果应该如下所示:
[
{
x: '2019-01-09',
y: 10, // a total of on the first day
},
{
x: '2019-01-10',
y: 15, // a total of on the second day (10 + 5)
},
{
x: '2019-01-11',
y: 35, // a total of on the third day (15 + 20)
}
]
所以基本上我不想要每天的数量而是增长。
P.S.: 我正在使用此数据显示在图表中。
聚合框架独立处理所有文档(按设计),因此它们彼此不了解。改变它的唯一方法是使用 $group. Setting _id
to null
allows you to capture the data from all documents into single one. Then you can iterate through that arrays (using $range to get the array of indexes and $map to return another array). It's easy to get x
($arrayElemAt) and for y
you need to sum all array elements using $reduce. The input for $reduce
is generated by $slice operator and depends on an index (for 0
it will be [10]
, for 1
[10,5]
and so on). To finalize the query you need $unwind and $replaceRoot 获取原始文档形状。
db.col.aggregate([
{
$sort: { x: 1 }
},
{
$group: {
_id: null,
xArr: { $push: "$x" },
yArr: { $push: "$y" }
}
},
{
$project: {
data: {
$map: {
input: { $range: [ 0, { $size: "$xArr" } ] },
as: "i",
in: {
x: { $arrayElemAt: [ "$xArr", "$$i" ] },
y: {
$reduce: {
input: { $slice: [ "$yArr", { $add: [ "$$i", 1 ] } ] },
initialValue: 0,
in: { $add: [ "$$this", "$$value" ] }
}
}
}
}
}
}
},
{
$unwind: "$data"
},
{
$replaceRoot: {
newRoot: "$data"
}
}
])
我想您需要将上述步骤附加到现有聚合中。为了证明它有效,您可以 运行 将其单独收集:
db.col.save({ x: '2019-01-09', y: 10 })
db.col.save({ x: '2019-01-10', y: 5 })
db.col.save({ x: '2019-01-11', y: 20 })
它输出:
{ "x" : "2019-01-09", "y" : 10 }
{ "x" : "2019-01-10", "y" : 15 }
{ "x" : "2019-01-11", "y" : 35 }
您可以在已有的基础上添加以下阶段
逻辑是 $push
x 和 y 到数组,使用 $range
按索引迭代数组,对于 x get $arrayElemAt
at index
,对于 y $slice
和 $sum
直到 index+1
db.t51.aggregate([
{$group : {_id : null, x : {$push : "$x"}, y : {$push : "$y"}}},
{$project : {data : {
$map : {
input : {$range : [0, {$size : "$x"}]},
as : "idx",
in : { x : {$arrayElemAt : ["$x", "$$idx"]}, y : {$sum : {$slice : ["$y", {$sum : ["$$idx",1]}]}}}}
}}},
{$unwind : "$data"},
{$replaceRoot: {newRoot : "$data"}}
]).pretty()
如果您有更多字段需要汇总或预测,您可以使用以下阶段
db.t51.aggregate([
{$group : {_id : null, data : {$push : "$$ROOT"}}},
{$addFields : {data :
{$reduce : {
input : "$data",
initialValue : [{y : 0}],
in : {$concatArrays : [ "$$value",[{$mergeObjects : ["$$this", { y : {$sum : ["$$this.y",{$arrayElemAt : ["$$value.y", -1]}]}}]}]]}
}}
}},
{$addFields : {data : {$slice : ["$data", 1, {$size : "$data"}]}}},
{$unwind : "$data"},
{$replaceRoot: {newRoot : "$data"}}
]).pretty()