如果您不知道密钥或无法做出合理的有根据的猜测,那么您基本上无法继续使用聚合框架。您可以提供“所有密钥”以供考虑,但我怀疑您的实际数据看起来更像这样:
{ "data": [{ "film": 10 }, { "televsion": 5 },{ "boardGames": 1 }] }
所以在这里找出所有“键名”然后将其扔到聚合语句中没有什么意义。
不过,为了记录,“这就是为什么你没有像这样构建数据存储的原因”。此处的“电影”等信息不应用作“关键”名称,因为它是有用的“数据”,可以在数据库系统中搜索,最重要的是“索引”。
所以你的数据应该看起来像这样:
{
"data": [
{ "type": "film", "value": 10 },
{ "type": "televsion", "valule": 5 },
{ "type": "boardGames", "value": 1 }
]
}
那么聚合语句就很简单了,其他很多事情也一样:
db.collection.aggregate([
{ "$unwind": "$data" },
{ "$group": {
"_id": null,
"sum": { "$sum": "$data.value" },
"avg": { "$avg": "$data.value" }
}}
])
但是由于文档中键名是不断变化的,并且没有统一的结构,那么就需要在服务器端进行 JavaScript 处理来遍历这些键,也就是 mapReduce:
db.collection.mapReduce(
function() {
this.data.forEach(function(data) {
Object.keys(data).forEach(function(key) {
emit(null,data[key]); // emit the value regardless of key name
});
});
},
function(key,values) {
return Array.sum(values); // Just summing for example
},
{ "out": { "inline": 1 } }
)
当然,这里的 JavaScript 执行将比聚合框架可用的本机编码运算符慢得多。
所以这应该是一个关于为什么在数据库中存储数据时不使用“数据”作为“键名”的惨痛教训。聚合框架与标准结构一起工作并且速度很快,回退到 JavaScript 处理更灵活,但成本主要在于速度和其他功能。