>我在 collecton 中有 1000 条用户记录,其中 459 条文档的性别为男性,其余为女性
//document structure
> db.user_details.find().pretty()
{
"_id" : ObjectId("557e610d626754910f0974a4"),
"id" : 0,
"name" : "Leanne Flinn",
"email" : "leanne.flinn@unilogic.com",
"work" : "Unilogic",
"dob" : "Fri Jun 11 1965 20:50:58 GMT+0530 (IST)",
"age" : 5,
"gender" : "female",
"salary" : 35696,
"hobbies" : "Acrobatics,Meditation,Music"
}
{
"_id" : ObjectId("557e610d626754910f0974a5"),
"id" : 1,
"name" : "Edward Young",
"email" : "edward.young@solexis.com",
"work" : "Solexis",
"dob" : "Wed Feb 12 1941 16:45:53 GMT+0530 (IST)",
"age" : 1,
"gender" : "female",
"salary" : 72291,
"hobbies" : "Acrobatics,Meditation,Music"
}
{
"_id" : ObjectId("557e610d626754910f0974a6"),
"id" : 2,
"name" : "Haydee Milligan",
"email" : "haydee.milligan@dalserve.com",
"work" : "Dalserve",
"dob" : "Tue Sep 13 1994 13:45:04 GMT+0530 (IST)",
"age" : 17,
"gender" : "male",
"salary" : 20026,
"hobbies" : "Papier-Mache"
}
{
"_id" : ObjectId("557e610d626754910f0974a7"),
"id" : 3,
"name" : "Lyle Keesee",
"email" : "lyle.keesee@terrasys.com",
"work" : "Terrasys",
"dob" : "Tue Apr 25 1922 13:39:46 GMT+0530 (IST)",
"age" : 79,
"gender" : "female",
"salary" : 48032,
"hobbies" : "Acrobatics,Meditation,Music"
}
{
"_id" : ObjectId("557e610d626754910f0974a8"),
"id" : 4,
"name" : "Shea Mercer",
"email" : "shea.mercer@pancast.com",
"work" : "Pancast",
"dob" : "Mon Apr 08 1935 06:10:30 GMT+0530 (IST)",
"age" : 51,
"gender" : "male",
"salary" : 31511,
"hobbies" : "Acrobatics,Photography,Papier-Mache"
}
每个性别的用户数
> db.user_details.find({gender:'male'}).count()
459
>
> db.user_details.find({gender:'female'}).count()
541
> db.user_details.find({name:{$ne:null}}).count()
1000
> db.user_details.find({age:{$ne:null}}).count()
1000
映射缩减代码
mapper = function(){
emit(this.gender, {name:this.name,age:this.age})
}
reducer = function(gender, users){
var res = 0;
users.forEach(function(user){
res = res + 1
})
return res;
}
db.user_details.mapReduce(mapper, reducer, {out: {inline:1}})
为什么地图归约结果只有 112 个文档?它应该分别包含男性和女性的 459 和 541,不是吗?
// Map reduce result
{
"results" : [
{
"_id" : "female",
"value" : 56
},
{
"_id" : "male",
"value" : 46
}
],
"timeMillis" : 45,
"counts" : {
"input" : 1000,
"emit" : 1000,
"reduce" : 20,
"output" : 2
},
"ok" : 1
}
注意:我知道这不是使用地图减少的正确方法,实际上我在地图减少中遇到了一些更令人毛骨悚然的问题。一旦我解决了这个问题,我就可以解决这个问题
你的问题是你错过了mapReduce如何工作的核心概念之一。解释这一点的相关文档可在此处找到:
- MongoDB可以为同一个键多次调用reduce函数。在这种情况下,该键的 reduce 函数的先前输出将成为该键的下一个 reduce 函数调用的输入值之一。
然后过了一会儿:
- 返回对象的类型必须与 Map 函数发出的值的类型相同
这两个语句的意思是,您需要使用映射器和化简器函数发出的完全相同的签名,因为reduce过程确实会被称为"多次"。
这就是mapReduce处理大数据的方式,但不一定一次处理给定"键"的所有相同值,而是在增量"块"中完成:
如果你在输出中想要的只是一个"数字",那么你"发射"的只是一个"数字":
db.collection.mapReduce(
function() {
emit(this.gender, this.age);
},
function(key,values) {
return Array.sum( values )
},
{ "out": { "inline": 1 } }
)
或者只是按类型"计数":
db.collection.mapReduce(
function() {
emit(this.gender, 1);
},
function(key,values) {
return Array.sum( values )
},
{ "out": { "inline": 1 } }
)
关键是"你需要拿出和你放进去的东西一样的东西",因为它可能会"再次放回去"。因此,无论您要收集什么数据,映射器和化简器的输出结构都必须相同。
这可能是错误的。
users.forEach(function(user){
res = res + 1
})
试试这个,
function(gender, users){
return Array.sum( users)
}
reduce函数中有一个错误。
MONGODB reduce函数可以针对同一个键多次调用,因此在您的reduce代码中,它会被覆盖。
同样在映射函数中,您正在输出结构 { user, age} 的文档,但在减少函数中,您正在返回计数。
reduce = function(gender, doc) {
reducedVal = { user: 0, age: 0 };
for (var idx = 0; idx < doc.length; idx++) {
reducedVal.user += 1 ;
reducedVal.age += 1;
}
return reducedVal;
};
请同时查看以下链接:
http://thejackalofjavascript.com/mapreduce-in-mongodb/
这是使用 map reduce() 的正确方法,用于显示用户的性别计数
db.yourCollectionName.mapReduce(
function(){
emit(this.gender,1);
},
function(k,v){
return Array.sum(v);
},
{out:"genderCount"}
);
db.genderCount.find();