使用如下所示的文档,我试图汇总数据,以便最终输出为每个用户received
和sent
值的总和。
文档
{
"_id" : 1,
"received" : [
{ "name" : "david", "value" : 15 },
{ "name" : "sarah", "value" : 10 },
{ "name" : "sarah", "value" : 15 }
],
"sent" : [
{ "name" : "david", "value" : 10 },
{ "name" : "sarah", "value" : 20 },
{ "name" : "david", "value" : 15 }
]
}
所需结果(或类似结果)
{
"name": "david",
"received": 15,
"sent": 25
},
{
"name": "sarah",
"received": 25,
"sent": 20
}
我试图平息接收和发送的邮件,但最终会出现很多重复,老实说,我不知道是否可以在不先将数据集带入客户端的情况下创建这种输出。
对StackOverflow的进一步搜索使我进入mongodb aggregate multiple arrays,它提供了合适的答案。我已将其标记为重复。
我根据上述帖子创建的最终解决方案如下;
[
{
'$addFields': {
'received.type': 'received',
'sent.type': 'sent'
}
}, {
'$project': {
'movements': {
'$concatArrays': [
'$received', '$sent'
]
}
}
}, {
'$unwind': {
'path': '$movements'
}
}, {
'$project': {
'name': '$movements.name',
'type': '$movements.type',
'value': '$movements.value'
}
}, {
'$group': {
'_id': '$name',
'sent': {
'$sum': {
'$cond': {
'if': {
'$eq': [
'$type', 'sent'
]
},
'then': '$value',
'else': 0
}
}
},
'received': {
'$sum': {
'$cond': {
'if': {
'$eq': [
'$type', 'received'
]
},
'then': '$value',
'else': 0
}
}
}
}
}
]
答案 0 :(得分:2)
在顶部添加$match
阶段以过滤文档
$facet
通过在同一文档上发送和接收来计算两个不同的结果$group
合并上一阶段的发送者和接收者字段$unwind
和$unwind
展开数组的合并数组$replaceRoot
用byBoth替换root $group
将结果合并回$project
仅用于过滤和投影必填字段聚合管道
db.ttt.aggregate([
{$facet : {
"byReceived" :[
{$unwind : "$received"},
{$group: {_id : "$received.name", received : {$sum : "$received.value"}}}
],
"bySent" :[
{$unwind : "$sent"},
{$group: {_id : "$sent.name", sent : {$sum : "$sent.value"}}}
]
}},
{$group: {_id:null, byBoth : {$push :{$concatArrays : ["$bySent", "$byReceived"]}}}},
{$unwind : "$byBoth"},
{$unwind : "$byBoth"},
{$replaceRoot: { newRoot: "$byBoth" }},
{$group : {_id : "$_id", sent : {$sum : "$sent"}, received : {$sum : "$received"}}},
{$project : {_id:0, name:"$_id", sent:"$sent", received:"$received"}}
])
结果
{ "name" : "david", "sent" : 25, "received" : 15 }
{ "name" : "sarah", "sent" : 20, "received" : 25 }