如何在 MongoDB 中按键聚合数组值对象
How to aggregate array value objects by key in MongoDB
给出以下集合
{ "_id": 1, "items": [ { "k": "A", "v": 1 }, { "k": "B", "v": 2 } ] }
{ "_id": 2, "items": [ { "k": "A", "v": 3 }, { "k": "B", "v": 4 } ] }
如何对具有相同键 k
的所有项求和,同时保留原始对象格式,如下所示:
{ "items": [ { "k": "A", "v": 4 }, { "k": "B", "v": 6 } ] }
我尝试使用 $unwind
和 $group
,但它 returns 对象序列而不是单个项目。
{ $unwind: { path: "$items" } },
{
$group: {
_id: "$items.k",
v: { $sum: "$items.v" }
}
}
我可以把它聚合回原来的格式,但我觉得一定有更好的方法。
$unwind
解构items
数组
$group
通过 items.k
得到 v
的总和
$group
为 null 并重构 items
数组
db.collection.aggregate([
{ $unwind: "$items" },
{
$group: {
_id: "$items.k",
v: { $sum: "$items.v" }
}
},
{
$group: {
_id: null,
items: {
$push: {
k: "$_id",
v: "$v"
}
}
}
}
])
您可以使用自定义 $accumulator 以您想要的方式合并对象:
db.collection.aggregate([
{$project: {
items: {
$arrayToObject: "$items"
}
}},
{$group: {
_id: null,
items: {
$accumulator: {
init: function(){ return {}; },
accumulate: function(obj, doc){
Object.keys(doc).forEach(function(k){
obj[k] = (obj[k]?obj[k]:0) + doc[k];
})
return obj;
},
accumulateArgs: ["$items"],
merge: function(obj, doc){
Object.keys(doc).forEach(function(k){
obj[k] = (obj[k]?obj[k]:0) + doc[k];
})
return obj;
}
}
}
}},
{$project:{
_id:0,
items:{$objectToArray:"$items"}
}}
])
给出以下集合
{ "_id": 1, "items": [ { "k": "A", "v": 1 }, { "k": "B", "v": 2 } ] }
{ "_id": 2, "items": [ { "k": "A", "v": 3 }, { "k": "B", "v": 4 } ] }
如何对具有相同键 k
的所有项求和,同时保留原始对象格式,如下所示:
{ "items": [ { "k": "A", "v": 4 }, { "k": "B", "v": 6 } ] }
我尝试使用 $unwind
和 $group
,但它 returns 对象序列而不是单个项目。
{ $unwind: { path: "$items" } },
{
$group: {
_id: "$items.k",
v: { $sum: "$items.v" }
}
}
我可以把它聚合回原来的格式,但我觉得一定有更好的方法。
$unwind
解构items
数组$group
通过items.k
得到v
的总和
$group
为 null 并重构items
数组
db.collection.aggregate([
{ $unwind: "$items" },
{
$group: {
_id: "$items.k",
v: { $sum: "$items.v" }
}
},
{
$group: {
_id: null,
items: {
$push: {
k: "$_id",
v: "$v"
}
}
}
}
])
您可以使用自定义 $accumulator 以您想要的方式合并对象:
db.collection.aggregate([
{$project: {
items: {
$arrayToObject: "$items"
}
}},
{$group: {
_id: null,
items: {
$accumulator: {
init: function(){ return {}; },
accumulate: function(obj, doc){
Object.keys(doc).forEach(function(k){
obj[k] = (obj[k]?obj[k]:0) + doc[k];
})
return obj;
},
accumulateArgs: ["$items"],
merge: function(obj, doc){
Object.keys(doc).forEach(function(k){
obj[k] = (obj[k]?obj[k]:0) + doc[k];
})
return obj;
}
}
}
}},
{$project:{
_id:0,
items:{$objectToArray:"$items"}
}}
])