对 mongo-db 中的 mapReduce 查询的响应不正确



>我在 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();

最新更新