这不是一个很好的文件结构,如果你打算跨汇总统计的“钥匙“就是这样。无论如何,它并不是真正的“数据作为关键字”的粉丝,但主要的一点是,由于关键名称在任何地方都不一样,所以许多MongoDB查询表单并没有“发挥出色”。
特别是与聚合框架,一种更好的方式来存储数据是一个实际的阵列中,像这样:
{
"_id": ObjectId("54cd5e7804f3b06c3c247428"),
"countries": [
{ "key": "AE", "value": NumberLong("13"),
{ "key": "RU", "value": NumberLong("16"),
{ "key": "BA", "value": NumberLong("10")
]
}
这样,您可以简单地使用聚合操作:
db.collection.aggregate([
{ "$unwind": "$countries" },
{ "$group": {
"_id": "$countries.key",
"value": { "$sum": "$countries.value" }
}}
])
这会给你如下结果:
{ "_id": "AE", "value": NumberLong(13) },
{ "_id": "RU", "value": NumberLong(28) }
这种结构确实“玩得很好”使用聚合框架和其他MongoDB查询模式,因为当你想以这种方式使用数据时,它确实是“预期”完成的。
在不改变文档的结构你不得不使用JavaScript的评价方法,以遍历您的文件的密钥,因为这是MongoDB的做到这一点的唯一方法:
db.collection.mapReduce(
function() {
var country = this.country_json;
Object.keys(country).forEach(function(key) {
emit(key, country[key]);
});
},
function(key,values) {
return values.reduce(function(p,v) { return NumberLong(p+v) });
},
{ "out": { "inline": 1 } }
)
这将产生与汇总示例输出中显示的结果完全相同的结果,但使用当前文档结构。当然,JavaScript评估的使用并不像聚合框架使用的本地方法那样高效,所以它不会很好地执行。
此外还要注意可能存在的问题,因为您的铸造NumberLong
字段中的“较大值”,因为它们表示为通往JavaScipt的主要原因是JavaScipt本身对该值的大小有限制,而不是可表示的大小。可能你的价值观只是微不足道的,但是这样简单地“施放”,但是如果意图的数量够大,那么数学就会失败。
因此,考虑改变构造这些数据的方式以使事情变得更容易通常是一个好主意。最后要说明的是,您希望使用单个文档中所有键的输出类型与直觉相反,因为它需要遍历“散列/映射”的键,而不是使用数组或游标的自然迭代器。
'country_json'不是你刚才提到的数组。您是否想将它作为一系列文档存储或如示例中所示? – BatScream 2015-02-09 11:11:18
喜欢它在实验中显示 – amic 2015-02-09 11:26:29