我当前正在使用MongoDB进行一些基本的MapReduce。
我目前有看起来像这样的数据:
db.football_team.insert({name: "Tane Shane", weight: 93, gender: "m"});
db.football_team.insert({name: "Lily Jones", weight: 45, gender: "f"});
...
我想通过性别创建一个mapReduce函数,并显示
- 每个性别的总数,男性&女
- 每个性别的平均体重
我可以创建一个地图/减少功能以单独执行每个功能,只是无法围绕如何显示两者的输出。我猜想,由于分组基于性别,地图功能应该保持不变,并且只需更改某些内容,他就会减少部分...
工作到目前为止的工作
var map1 = function()
{var key = this.gender;
emit(key, {count:1});}
var reduce1 = function(key, values)
{var sum=0;
values.forEach(function(value){sum+=value["count"];});
return{count: sum};};
db.football_team.mapReduce(map1, reduce1, {out: "gender_stats"});
输出
db.football_team.find()
{"_id" : "f", "value" : {"count": 12} }
{"_id" : "m", "value" : {"count": 18} }
谢谢
在任何实现中"映射/降低"的关键规则基本上是, mapper 也由降低器返回。造成这种情况的关键原因是"映射/减少"在概念上的工作方式的一部分是多次调用降低器。这基本上意味着您可以在已经从先前通过的 reducer 以及来自 mapper mapper sapper 降低器 restager 。
mongoDB可以为同一键调用降低功能。在这种情况下,该密钥的降低函数的先前输出将成为该键的下一个降低功能调用的输入值之一。
也就是说,您最好的"平均"方法是 total 以及 count 的数据,然后简单地将两者划分。实际上,这将"映射/降低"操作添加为A 最终确定函数。
db.football_team.mapReduce(
// mapper
function() {
emit(this.gender, { count: 1, weight: this.weight });
},
// reducer
function(key,values) {
var output = { count: 0, weight: 0 };
values.forEach(value => {
output.count += value.count;
output.weight += value.weight;
});
return output;
},
// options and finalize
{
"out": "gender_stats", // or { "inline": 1 } if you don't need another collection
"finalize": function(key,value) {
value.avg_weight = value.weight / value.count; // take an average
delete value.weight; // optionally remove the unwanted key
return value;
}
}
)
一切都很好,因为 mapper 和 reducer 都在发出具有相同 shape 的数据,并且也期望输入该 Shape 在还原器本身中。当然,最终确定方法当然只是在所有"还原" 最终完成后才调用,并且只需处理每个结果。
如前所述,aggregate()
方法实际上更有效地进行了此操作,并且在本机编码方法中不会引起服务器端JavaScript解释和执行的开销(和潜在安全风险(:
db.football_team.aggregate([
{ "$group": {
"_id": "$gender",
"count": { "$sum": 1 },
"avg_weight": { "$avg": "$weight" }
}}
])
基本上就是这样。此外,您实际上可以继续并在 之后做其他事情 $group
管道阶段(或任何阶段(以您无法使用mongoDB mapReduce
实现方式。值得注意的是,例如将$sort
应用于结果:
db.football_team.aggregate([
{ "$group": {
"_id": "$gender",
"count": { "$sum": 1 },
"avg_weight": { "$avg": "$weight" }
}},
{ "$sort": { "avg_weight": -1 } }
])
mapReduce
允许的唯一排序完全是 key emit
使用的是始终em>上升订单。但是您不能以任何其他方式 sort 汇总结果在输出中,当然没有在输出到另一个集合时执行查询,也可以通过"在存储器中工作",并从中返回的结果服务器。
作为" side Note" (尽管很重要(,您可能还应在" Learning" 中考虑现实是" server-Side JavaScript" MongoDB的功能实际上是的工作 - 是特征。当首次引入MongoDB时,它将JavaScript引擎应用于服务器执行,主要是为了弥补尚未实现的功能。
因此,弥补了缺乏许多查询操作员的完整实现和将来会出现的聚合功能,添加JavaScript引擎是" Quick Fix" 为了使某些事情以最小的实现来完成。
多年来的结果是这些JavaScript引擎功能逐渐被删除。删除API的group()
函数。API的eval()
函数被弃用并计划在下一个主要版本中删除。对于这些JavaScript在服务器功能上的有限的未来,写作基本上是"在墙上" ,因为清晰的模式是 andation 功能为某物提供支持的位置,然后需要继续支持JavaScript引擎的需求基本上消失了。
这里的核心智慧是,专注于学习服务器功能上的这些JavaScript,除非您有一个紧迫的用例,否则可能真的不值得投入时间。