在任何实现中“map/reduce”的关键规则基本上是same shape of data needs to be emitted by the mapper as is also returned by the reducer. 这样做的关键原因是“map/reduce”在概念上如何通过很可能调用 reducer 多次。这基本上意味着您可以调用您的 reducer 函数,该输出已经从上一次通过 reducer 发出的输出以及来自 mapper 的其他数据.
MongoDB 可以为同一个键多次调用 reduce 函数。在这种情况下,该键的reduce函数的先前输出将成为该键的下一个reduce函数调用的输入值之一。
也就是说,“平均”的最佳方法是总计数据和计数,然后简单地将两者相除。这实际上为“map/reduce”操作添加了另一个步骤,作为 finalize 函数。
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 em> 在 reducer 本身内。当然,finalize 方法只是在所有 "reducing" 最终完成并处理每个结果之后才调用。
尽管如此,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 允许的唯一排序是与emit 一起使用的key是always 按升序顺序排序。但是您不能以任何其他方式排序输出中的聚合结果,当然在输出到另一个集合时不执行查询,或者通过“在内存中”使用返回的结果服务器。
作为“旁注”(虽然很重要),您可能还应该在“学习”中考虑到现实是“服务器- MongoDB 的侧 JavaScript" 功能实际上是一个解决方法,而不是一个功能。 MongoDB 刚推出时,它使用 JavaScript 引擎进行服务器执行,主要是为了弥补尚未实现的功能。
因此弥补许多查询运算符和聚合函数的完整实现(稍后会出现),添加 JavaScript 引擎是一个“快速修复”允许以最少的实现来完成某些事情。
这些年来的结果是那些 JavaScript 引擎功能 正在逐渐被删除。 API 的group() 函数被移除。 API 的 eval() 函数已弃用,并计划在下一个主要版本中删除。对于这些 JavaScript 在服务器功能上的有限未来,写作基本上是“在墙上”,因为明确的模式是 native 功能为某些东西提供支持,然后基本上不再需要继续支持 JavaScript 引擎了。
这里的核心智慧是专注于学习这些服务器特性上的 JavaScript,可能不值得投入时间,除非你有一个目前无法通过任何其他方式解决的紧迫用例.