我有一个跟踪不同城市人口的数据结构:
//in db.persons
{
name: "John",
city: "Seattle
},
{
name: "Bill",
city: "Portland"
}
我想运行地图缩小以获取每个城市中有多少人的列表,因此结果将如下所示:
{
_id: "Seattle",
value: 10
}
我的地图缩小功能如下所示:
map = function(){
var city = this.city
emit(city, 1);
};
reduce = function(key, values){
var result = 0;
values.forEach(function(value){
result += 1;
});
return result;
}
非常简单的东西,我认为将city
作为关键字,然后在找到的每个匹配城市的结果中添加一个。但是,在生成的地图缩小时,该值偏差很大。将我的reduce函数切换为:
reduce = function(key, values){
var result = 0;
values.forEach(function(value){
result += value;
});
return result;
}
将value
添加到结果中(应该是1,正如我从emit
函数中理解的那样)返回了正确的结果。
为什么结果不同?我的value
在reduce函数中不是1吗?
答案 0 :(得分:1)
这是因为MongoDB可以为同一个密钥多次调用reduce函数。这是一个简单的工作示例:
假设您的数据库中只有三个文档,每个文档都具有相同的“城市”“西雅图”。在发射阶段之后,您将拥有一组看起来像
的发射对象 {'Seattle' : 1}. {'Seattle' : 1}. {'Seattle' : 1}
发射阶段完成后,减速阶段开始。在最简单的情况下,reduce函数将被称为reduce('Seattle', [1,1,1])
。在这种情况下,您的第一个功能将正常工作。但是,reduce函数可以多次调用:
reduce('Seattle', [1,1]) -> {'Seattle' : 2}, {'Seattle', 1}
reduce('Seattle', [2,1])
在这种情况下,您的第一个reduce函数将在第二个reduce调用之后返回2
,因为值列表中有两个项目。在你的第二个reduce函数中,你正确地将值加在一起而不是仅计算它们,这给出了正确的答案。
我个人认为CouchDB docs稍微更好地解释了为什么你需要为它们的值输入数组设置交换和关联递减函数。