我是MongoDB的新手。我想知道是否可以聚合数组中的每个“列”。假设我们有以下文件:
db.test.insert([{"player": "A", "year": 2010, "value": [1, 1 ]},
{"player": "A", "year": 2011, "value": [2, 1 ]},
{"player": "A", "year": 2012, "value": [2, 1 ]},
{"player": "B", "year": 2010, "value": [1, 2 ]}])
预期结果应该是:
[
{
"player": "A",
"sum_result": [
5,
3
]
},
{
"player": "B",
"sum_result": [
1,
2
]
}
]
是否可以在不使用Map / Reduce的情况下执行此操作?下面的链接显示了map / reduce解决方案,但我正在寻找另一种方法来实现相同的目标。谢谢!
Mongodb: aggregate array of integers for each array position
答案 0 :(得分:0)
只有当文件中的元素可以通过路径名到达时,大多数问题才能在聚合中解决。
在此示例中,路径values
或values.0
无法访问values.1
数组元素 。
因此,要解决此类问题,您需要选择map-reduce
,这样可以提供更大的灵活性。
不幸的是,除非您更改架构,否则在这种情况下无法使用聚合获得所需的输出。其中一个例子是制作values
字段 - 一组文档。在这里,值数组中的所有元素都可以通过路径名来访问,例如values.c1
(表示列1
中的值)
db.t.insert([
{"player":"A","year":2010,"value":[ {"c1":1}, {"c2":1}]},
{"player":"A","year":2011,"value":[ {"c1":2}, {"c2":1}]},
{"player":"A","year":2012,"value":[ {"c1":2}, {"c2":1}]},
{"player":"B","year":2010,"value":[ {"c1":1}, {"c2":2}]}
])
然后您可以将其汇总如下:
db.t.aggregate([
{$unwind:"$value"},
{$group:{"_id":"$player",
"c1":{$sum:"$value.c1"},
"c2":{$sum:"$value.c2"}}},
{$group:{"_id":"$_id",
"c1":{$push:{"c1":"$c1"}},
"c2":{$push:{"c2":"$c2"}}}},
{$project:{"value":{$setUnion:["$c1","$c2"]}}}
])
O / P:
{ "_id" : "A", "value" : [ { "c1" : 5 }, { "c2" : 3 } ] }
{ "_id" : "B", "value" : [ { "c2" : 2 }, { "c1" : 1 } ] }
由于解决方案涉及$unwind操作,这是昂贵的,我建议您根据数据集衡量两种解决方案的性能,并选择最适合您应用的解决方案。
答案 1 :(得分:0)
感谢您的回复。更改架构可能是解决此问题的最佳方法。正如您所指出的, $ unwind 操作可能代价高昂。我最终决定使用以下解决方案。
修订文件:
db.test.insert([{"player": "A", "year": 2010, "values": {"v1":1, "v2":1 }},
{"player": "A", "year": 2011, "values": {"v1":2, "v2":1 }},
{"player": "A", "year": 2012, "values": {"v1":2, "v2":1 }},
{"player": "B", "year": 2010, "values": {"v1":1, "v2":2 }}])
查询声明:
db.test.aggregate([
{$group:{"_id":"$player",
"v1":{$sum:"$values.v1"},
"v2":{$sum:"$values.v2"}}},
{$project:{"values":{"v1":"$v1","v2":"$v2"}}}
])
输出:
{
"result": [{
"_id": "B",
"values": {
"v1": 1,
"v2": 2
}
}, {
"_id": "A",
"values": {
"v1": 5,
"v2": 3
}
}],
"ok": 1
}