我使用MongoDB聚合API每天聚合一些数据。 这种聚合的结果具有以下格式:
[
{
aggDate: '2019-05-23',
results: [
{
foo: 0.58,
bar: 0.42
}, {
foo: 0.32,
bar: 0.98
}
]
}
]
关于日期的聚合很好,但是现在我想聚合results
数组中的对象。
此聚合的结果应采用以下格式:
[
{
aggDate: '2019-05-23',
result: {
foo: 0.45 // avg of all the `foo`, here: (0.58 + 0.32) / 2
bar: 0.7 // avg of all the `bar`, here: (0.42 + 0.98) / 2
}
}
]
我的问题是键foo
和bar
可以更改/可以在results
对象中添加新字段。为了避免每次发生查询时都重新编码,我想使用某种通用的方式对MongoDB进行说明
采用此对象数组并将其简化为单个对象,其中每个值都是所有对象中同一字段的平均值。
我知道MongoDB中存在$reduce
运算符,但是我不知道如何使用它,甚至不确定它是否可以在这里为我提供帮助。
答案 0 :(得分:4)
您应该运行$unwind并使用$group阶段汇总数据。您还需要$arrayToObject和$objectToArray才能使用动态键。 $reduce在这里是不可选择的,因为键是unknwon
db.col.aggregate([
{
$project: {
aggDate: 1,
results: {
$map: { input: "$results", in: { $objectToArray: "$$this" } }
}
}
},
{
$unwind: "$results"
},
{
$unwind: "$results"
},
{
$group: {
_id: { aggDate: "$aggDate", k: "$results.k" },
sum: { $sum: "$results.v" },
count: { $sum: 1 }
}
},
{
$project: {
_id: 1,
v: { $divide: [ "$sum", "$count" ] }
}
},
{
$group: {
_id: "$_id.aggDate",
results: { $push: { k: "$_id.k", v: "$v" } }
}
},
{
$project: {
_id: 0,
aggDate: "$_id",
results: { $arrayToObject: "$results" }
}
}
])
答案 1 :(得分:3)
您不需要使用$reduce
。只需$sum
即可完成工作。
db.collection.aggregate([
{ "$project": {
"result": {
"foo": { "$divide": [{ "$sum": "$results.foo" }, { "$size": "$results" }] },
"bar": { "$divide": [{ "$sum": "$results.bar" }, { "$size": "$results" }] }
}
}}
])
根据{{1}}数组中的动态键更新->
results
具有更简化的版本和单个db.collection.aggregate([
{ "$project": {
"aggDate": 1,
"results": {
"$reduce": {
"input": {
"$map": { "input": "$results", "in": { "$objectToArray": "$$this" }}
},
"initialValue": [],
"in": { "$concatArrays": ["$$value", "$$this"] }
}
}
}},
{ "$project": {
"aggDate": 1,
"result": {
"$arrayToObject": {
"$map": { "input": { "$setUnion": ["$results.k"] },
"as": "m",
"in": {
"$let": {
"vars": {
"fil": {
"$filter": {
"input": "$results",
"as": "d",
"cond": { "$eq": ["$$d.k", "$$m"] }
}
}
},
"in": {
"k": "$$m",
"v": { "$divide": [{ "$sum": "$$fil.v" }, { "$size": "$$fil" }] }
}
}
}
}
}
}
}}
])
阶段
$project
两者都输出为
db.collection.aggregate([
{ "$project": {
"aggDate": 1,
"result": {
"$let": {
"vars": {
"red": {
"$reduce": {
"input": {
"$map": { "input": "$results", "in": { "$objectToArray": "$$this" }}
},
"initialValue": [],
"in": { "$concatArrays": ["$$value", "$$this"] }
}
}
},
"in": {
"$arrayToObject": {
"$map": { "input": { "$setUnion": ["$$red.k"] },
"as": "m",
"in": {
"$let": {
"vars": {
"fil": {
"$filter": {
"input": "$$red",
"as": "d",
"cond": { "$eq": ["$$d.k", "$$m"] }
}
}
},
"in": {
"k": "$$m",
"v": { "$divide": [{ "$sum": "$$fil.v" }, { "$size": "$$fil" }] }
}
}
}
}
}
}
}
}
}}
])
答案 2 :(得分:0)
编辑: 不是最优雅的,但是:
{
"$unwind" : "$result"
},
{
"$addFields" : {
"value" : {
"$objectToArray" : "$result"
}
}
},
{
"$unwind" : "$value"
},
{
"$group" : {
"_id" : null,
"length" : {
"$sum" : 1.0
},
"total" : {
"$sum" : "$value.v"
}
}
},
{
"$addFields" : {
"avg" : {
"$divide" : [
"$total",
"$length"
]
}
}
}