我在MongoDB中使用db.collection.aggregate时遇到了问题。
我的数据结构如下:
_id:...
Segment:{
"S1":1,
"S2":5,
...
"Sn":10
}
这意味着Segment
中的以下内容:我可能有几个带有数值的子属性。我想把它们总结为1 + 5 + .. + 10
问题是:我不确定子属性名称,因为每个文档的段号都不同。所以我无法列出每个细分名称。我只是想使用类似for循环的东西来将所有值加在一起。
我尝试了类似的查询:
db.collection.aggregate([
{$group:{
_id:"$Account",
total:{$sum:"$Segment.$"}
])
但它不起作用。
答案 0 :(得分:14)
你已经犯了经典错误,拥有任意字段名称。 MongoDB是“无架构的”,但这并不意味着您不需要考虑您的架构。键名应该是描述性的,在你的情况下,f.e。 “S2”并不意味着什么。为了进行大多数类型的查询和操作,您需要重新设计架构以存储您的数据,如下所示:
_id:...
Segment:[
{ field: "S1", value: 1 },
{ field: "S2", value: 5 },
{ field: "Sn", value: 10 },
]
然后,您可以运行以下查询:
db.collection.aggregate( [
{ $unwind: "$Segment" },
{ $group: {
_id: '$_id',
sum: { $sum: '$Segment.value' }
} }
] );
然后会产生类似这样的内容(使用您问题中唯一的文档):
{
"result" : [
{
"_id" : ObjectId("51e4772e13573be11ac2ca6f"),
"sum" : 16
}
],
"ok" : 1
}
答案 1 :(得分:0)
从Mongo 3.4
开始,这可以通过应用内联操作来实现,从而避免使用昂贵的操作,例如$group
:
// { _id: "xx", segments: { s1: 1, s2: 3, s3: 18, s4: 20 } }
db.collection.aggregate([
{ $addFields: {
total: { $sum: {
$map: { input: { $objectToArray: "$segments" }, as: "kv", in: "$$kv.v" }
}}
}}
])
// { _id: "xx", total: 42, segments: { s1: 1, s2: 3, s3: 18, s4: 20 } }
这个想法是将对象(包含相加的数字)转换为数组。这是$objectToArray
的角色,它从Mongo 3.4.4
开始将{ s1: 1, s2: 3, ... }
转换为[ { k: "s1", v: 1 }, { k: "s2", v: 3 }, ... ]
。这样,因为我们可以通过它们的"v"
字段访问值,所以我们不需要关心字段名称。
拥有一个数组而不是一个对象是能够求和其元素的第一步。但是用$objectToArray
获得的元素是对象,而不是简单的整数。我们可以通过映射($map
操作)这些数组元素以提取其"v"
字段的值来传递此信息。在我们的情况下,这会导致创建这种数组:[1, 3, 18, 42]
。
最后,使用$sum
操作简单地对数组中的元素求和即可。
答案 2 :(得分:0)
段:{s1: 10, s2: 4, s3: 12}
{$set: {"new_array":{$objectToArray: "$Segment"}}}, //makes field names all "k" or "v"
{$project: {_id:0, total:{$sum: "$new_array.v"}}}
“总数”将为 26。
$set 在较新版本的 mongo 中替换 $addFields。 (我使用的是 4.2。)
"new_array": [
{
"k": "s1",
"v": 10
},
{
"k": "s2",
"v": 4
},
{
"k": "s3",
"v": 12
}
]
您也可以使用正则表达式。例如。 /^s/i
表示以“s”开头的单词。