一个请求中的多个聚合函数
Multiple Aggregate functions in one request
我有一个数据集如下:
{
item: '123',
array: [{
array2:[{
array3: [{
property1: 1234
}]
}],
anotherArray: [{
property2: 1234
}]
}]
}
我试图在同一请求中汇总 属性2 和 属性 的总和。
这是我当前的聚合函数:
Item.aggregate([
{$match: {itemId: 1234}},
{$unwind: "$array"},
{$unwind: "$array.array2"},
{$unwind: "$array.array2.array3"},
{$unwind: "$array.anotherArray"},
{$group: {
_id: 0,
property1: {$sum: '$array.array2.array3.property1'},
property2: {$sum: '$array.anotherArray.property2'}
}},
{$project: {
_id: 0,
property1: "$property1",
property2: "$property2",
}},
], function (err, aggregate) {
callback(null, aggregate);
});
问题是 属性 1 和 2 的聚合结果始终是它们应有的值的两倍。
我想问题出在 "anotherArray" 的 $unwind 上,因为当我删除它时,我得到了正确的聚合值。
是否可以用一个聚合函数对多个数组进行聚合?
目前我只是通过异步并行向数据库发出 2 个不同的请求,但我想在将来进行更复杂的聚合而不进行额外的数据库调用。
如前所述,该结构不是一个好的结构,应该对其意图进行审查。真的不清楚为什么它如此结构化,或者在这两种情况下数组中的任何其他内容是否会弄乱这里的结果。
但是当文档中有多个数组时,有一种通用方法,基本上是分别处理每个数组并首先获取每个文档的 "totals"。然后将所有文档的总计相加:
Item.aggregate([
// Unwind only 1 inner array first
{ "$unwind": "$array" },
{ "$unwind": "$array.array2" },
{ "$unwind": "$array.array2.array3" },
// Group back the sum of the element and the first of the other array
// and only per document
{ "$group": {
"_id": "$_id",
"property1": { "$sum": "$array.array2.array3.property1" },
"anotherArray": { "$first": "$array.anotherArray" }
}},
// Unwind the other array
{ "$unwind": "$anotherArray" },
// Group back the total and the first summed per document
{ "$group": {
"_id": "$_id",
"property1": { "$first": "$property1" },
"property2": { "$sum": "$anotherArray.property2" }
}},
// Total all documents and output
{ "$group": {
"_id": null,
"property1": { "$sum": "$property1" },
"property2": { "$sum": "$property2" },
}},
{ "$project": {
"_id": 0,
"property1": 1,
"property2": 1
}}
],callback);
因此,通过一次仅包含一个数组并首先仅在原始文档中获取总计,您可以避免为另一个数组的每个未展开项目创建多个副本的重复问题。使用离散的文档总计,可以很容易地从您需要的选择中获得总计。
最后,我用 MongoDB $setUnion.
为我的用例找到了解决方案
这是我用于回答问题的代码:
Item.aggregate([
{$match: { itemID: '1234'}},
{$unwind: "$array1"},
{$unwind: "$array1.array2"},
{$project: {
_id: 0,
combined: {$setUnion: ['$array1.anotherArray', '$array1.array2.array3']},
}},
{$unwind: "$combined"},
{$group: {
_id: 0,
property1: {$sum: '$combined.property1'},
property2: {$sum: '$combined.property2'}
}},
], function (err, aggregate) {
cb(aggregate);
});
我有一个数据集如下:
{
item: '123',
array: [{
array2:[{
array3: [{
property1: 1234
}]
}],
anotherArray: [{
property2: 1234
}]
}]
}
我试图在同一请求中汇总 属性2 和 属性 的总和。 这是我当前的聚合函数:
Item.aggregate([
{$match: {itemId: 1234}},
{$unwind: "$array"},
{$unwind: "$array.array2"},
{$unwind: "$array.array2.array3"},
{$unwind: "$array.anotherArray"},
{$group: {
_id: 0,
property1: {$sum: '$array.array2.array3.property1'},
property2: {$sum: '$array.anotherArray.property2'}
}},
{$project: {
_id: 0,
property1: "$property1",
property2: "$property2",
}},
], function (err, aggregate) {
callback(null, aggregate);
});
问题是 属性 1 和 2 的聚合结果始终是它们应有的值的两倍。
我想问题出在 "anotherArray" 的 $unwind 上,因为当我删除它时,我得到了正确的聚合值。
是否可以用一个聚合函数对多个数组进行聚合?
目前我只是通过异步并行向数据库发出 2 个不同的请求,但我想在将来进行更复杂的聚合而不进行额外的数据库调用。
如前所述,该结构不是一个好的结构,应该对其意图进行审查。真的不清楚为什么它如此结构化,或者在这两种情况下数组中的任何其他内容是否会弄乱这里的结果。
但是当文档中有多个数组时,有一种通用方法,基本上是分别处理每个数组并首先获取每个文档的 "totals"。然后将所有文档的总计相加:
Item.aggregate([
// Unwind only 1 inner array first
{ "$unwind": "$array" },
{ "$unwind": "$array.array2" },
{ "$unwind": "$array.array2.array3" },
// Group back the sum of the element and the first of the other array
// and only per document
{ "$group": {
"_id": "$_id",
"property1": { "$sum": "$array.array2.array3.property1" },
"anotherArray": { "$first": "$array.anotherArray" }
}},
// Unwind the other array
{ "$unwind": "$anotherArray" },
// Group back the total and the first summed per document
{ "$group": {
"_id": "$_id",
"property1": { "$first": "$property1" },
"property2": { "$sum": "$anotherArray.property2" }
}},
// Total all documents and output
{ "$group": {
"_id": null,
"property1": { "$sum": "$property1" },
"property2": { "$sum": "$property2" },
}},
{ "$project": {
"_id": 0,
"property1": 1,
"property2": 1
}}
],callback);
因此,通过一次仅包含一个数组并首先仅在原始文档中获取总计,您可以避免为另一个数组的每个未展开项目创建多个副本的重复问题。使用离散的文档总计,可以很容易地从您需要的选择中获得总计。
最后,我用 MongoDB $setUnion.
为我的用例找到了解决方案这是我用于回答问题的代码:
Item.aggregate([
{$match: { itemID: '1234'}},
{$unwind: "$array1"},
{$unwind: "$array1.array2"},
{$project: {
_id: 0,
combined: {$setUnion: ['$array1.anotherArray', '$array1.array2.array3']},
}},
{$unwind: "$combined"},
{$group: {
_id: 0,
property1: {$sum: '$combined.property1'},
property2: {$sum: '$combined.property2'}
}},
], function (err, aggregate) {
cb(aggregate);
});