聚合来自两个数组的 $sum 值
Aggregate $sum values from two arrays
我有这个collection
{
"_id" : ObjectId("54f46f18c36dcc206d0cec38"),
"project" : 23123,
"title" : "Change of windows",
"description": "Change to better windows on building A"
"costs":[
{
category: 'Produktionskostnad',
value: 3000
},
{
category: 'Projekteringskostnad',
value: 2000
},
{
category: 'Overhead',
value: 1000
}
],
"energySaving" : [
{
"energy" : "electricity",
"type" : "lighting",
"value" : 24324
},
{
"energy" : "electricity",
"type" : "equipment",
"value" : 24324
},
{
"energy" : "electricity",
"type" : "fans",
"value" : 24324
},
{
"energy" : "electricity",
"type" : "distribution",
"value" : 24324
},
{
"energy" : "electricity",
"type" : "chiller",
"value" : 24324
},
{
"energy" : "electricity",
"type" : "other",
"value" : 24324
}
]
}
我需要一个聚合来计算总成本和总节能。
为了节省开支,我有以下查询:
db.collection.aggregate( [
{ $unwind: "$energySaving" },
{
$group: {
_id: {
title: '$title',
description: '$description'
},
totalEnergySaving: { $sum: '$energySaving.value' }
}
}
]);
但是如何计算同一查询中的总成本?我不能在同一查询中添加 $unwind 成本。我可以 "reset" $group 以某种方式再次查询吗?
TLDR;
在现代 MongoDB 版本中,我们只需简单地用 "double" 符号连续地为 "array sum" 和 "accumulator" 做一个 $group
since we can pass the array items directly to $sum
:
db.collection.aggregate([
{ "$group": {
"_id": {
"title": "$title",
"description": "$description"
},
"totalCosts": { "$sum": { "$sum": "$costs.value" } },
"totalEnergySaving": { "$sum": { "$sum": "$energySaving.value" } }
}}
])
2015 年原始答案
这需要一些技巧才能正确完成,但描述它的最佳方式是 "deal with grouping per document first" 然后 "group the totals later":
db.collection.aggregate([
// Do cost per document
{ "$unwind": "$costs" },
{ "$group": {
"_id": "$_id",
"title": { "$first": "$title" },
"description": { "$first": "$description" },
"totalCosts": { "$sum": "$costs.value" },
"energySaving": { "$first": "$energySaving" }
}},
// Do energy saving per document
{ "$unwind": "$energySaving" },
{ "$group": {
"_id": "$_id",
"title": { "$first": "$title" },
"description": { "$first": "$description" },
"totalCosts": { "$first": "$totalCosts" },
"totalEnergySaving": { "$sum": "$energySaving.value" }
}},
// Now sum the real grouping
{ "$group": {
"_id": {
"title": "$title",
"description": "$description"
},
"totalCosts": { "$sum": "$totalCosts" },
"totalEnergySaving": { "$sum": "$totalEnergySaving" }
}}
])
通过从数组值中计算出每个文档的奇异值,并通过展开和分组 "one array at a time" 来避免每个数组成员的项目复制,你形成了一个基础到你实际的奇异分组想要。
因此,当您 $unwind
一个数组时,您会得到文档的多个副本,每个数组成员现在在每个文档副本中表示为一个奇异值。你不想在这里做的是 $unwind
另一个数组,而你已经有一个未缠绕的数组,因为这将根据数组以相同方式拥有的成员数量创建尽可能多的 "more copies" 文档。
使用 $group
back to the document _id
value at this point ensures we are only working the the original parts of the document that was initially "un-wound". Normal grouping operators like $sum
still apply, but $first
可以用来提取 "only one" 那些复制的字段值 "outside the array" 和几乎 return 文档到它的 "original form"对于您要保留的字段以及您有意从数组内容中聚合的任何内容。
对每个你想要的数组重复,然后转到另一个 $group
语句,这次用你之前创建的新奇异求和值一次加起来不止一个文档。
这就是在任何级别的分组中添加多个数组项的过程。当然,如果无论如何唯一的分组是在文档级别完成的,那么您可以在对每个数组进行分组后放弃,或者确实接受无论如何在客户端代码中进行可能更好。
我有这个collection
{
"_id" : ObjectId("54f46f18c36dcc206d0cec38"),
"project" : 23123,
"title" : "Change of windows",
"description": "Change to better windows on building A"
"costs":[
{
category: 'Produktionskostnad',
value: 3000
},
{
category: 'Projekteringskostnad',
value: 2000
},
{
category: 'Overhead',
value: 1000
}
],
"energySaving" : [
{
"energy" : "electricity",
"type" : "lighting",
"value" : 24324
},
{
"energy" : "electricity",
"type" : "equipment",
"value" : 24324
},
{
"energy" : "electricity",
"type" : "fans",
"value" : 24324
},
{
"energy" : "electricity",
"type" : "distribution",
"value" : 24324
},
{
"energy" : "electricity",
"type" : "chiller",
"value" : 24324
},
{
"energy" : "electricity",
"type" : "other",
"value" : 24324
}
]
}
我需要一个聚合来计算总成本和总节能。
为了节省开支,我有以下查询:
db.collection.aggregate( [
{ $unwind: "$energySaving" },
{
$group: {
_id: {
title: '$title',
description: '$description'
},
totalEnergySaving: { $sum: '$energySaving.value' }
}
}
]);
但是如何计算同一查询中的总成本?我不能在同一查询中添加 $unwind 成本。我可以 "reset" $group 以某种方式再次查询吗?
TLDR;
在现代 MongoDB 版本中,我们只需简单地用 "double" 符号连续地为 "array sum" 和 "accumulator" 做一个 $group
since we can pass the array items directly to $sum
:
db.collection.aggregate([
{ "$group": {
"_id": {
"title": "$title",
"description": "$description"
},
"totalCosts": { "$sum": { "$sum": "$costs.value" } },
"totalEnergySaving": { "$sum": { "$sum": "$energySaving.value" } }
}}
])
2015 年原始答案
这需要一些技巧才能正确完成,但描述它的最佳方式是 "deal with grouping per document first" 然后 "group the totals later":
db.collection.aggregate([
// Do cost per document
{ "$unwind": "$costs" },
{ "$group": {
"_id": "$_id",
"title": { "$first": "$title" },
"description": { "$first": "$description" },
"totalCosts": { "$sum": "$costs.value" },
"energySaving": { "$first": "$energySaving" }
}},
// Do energy saving per document
{ "$unwind": "$energySaving" },
{ "$group": {
"_id": "$_id",
"title": { "$first": "$title" },
"description": { "$first": "$description" },
"totalCosts": { "$first": "$totalCosts" },
"totalEnergySaving": { "$sum": "$energySaving.value" }
}},
// Now sum the real grouping
{ "$group": {
"_id": {
"title": "$title",
"description": "$description"
},
"totalCosts": { "$sum": "$totalCosts" },
"totalEnergySaving": { "$sum": "$totalEnergySaving" }
}}
])
通过从数组值中计算出每个文档的奇异值,并通过展开和分组 "one array at a time" 来避免每个数组成员的项目复制,你形成了一个基础到你实际的奇异分组想要。
因此,当您 $unwind
一个数组时,您会得到文档的多个副本,每个数组成员现在在每个文档副本中表示为一个奇异值。你不想在这里做的是 $unwind
另一个数组,而你已经有一个未缠绕的数组,因为这将根据数组以相同方式拥有的成员数量创建尽可能多的 "more copies" 文档。
使用 $group
back to the document _id
value at this point ensures we are only working the the original parts of the document that was initially "un-wound". Normal grouping operators like $sum
still apply, but $first
可以用来提取 "only one" 那些复制的字段值 "outside the array" 和几乎 return 文档到它的 "original form"对于您要保留的字段以及您有意从数组内容中聚合的任何内容。
对每个你想要的数组重复,然后转到另一个 $group
语句,这次用你之前创建的新奇异求和值一次加起来不止一个文档。
这就是在任何级别的分组中添加多个数组项的过程。当然,如果无论如何唯一的分组是在文档级别完成的,那么您可以在对每个数组进行分组后放弃,或者确实接受无论如何在客户端代码中进行可能更好。