下面的例子是在小数据下测试的,我尝试在单机的千万级别测试,等很久都没结果…
数据有表:crawler.videos,表结构是: _id, playUrl, siteId…
只有_id是有索引的,siteId不同的值分别代表不同的网站。值有:1,2,3三个值。
现在要统计数据库中每个网站的所含有的id数。就是相当于在mySql中select count(_id),siteId from videos group by siteId 的语句。
以siteId分组,统计各siteId所含有的id数。在mongo中,可以通过group函数来做,也可以通过mapReduce来做,现记录两种做法:
通过group()函数
语法:
db.coll.group(
           {key: { fieldToGroup : true
 },
            cond: { condition_where },
            reduce: function(obj , prev) { logical_sentenct; },
            initial: { initial_values }
            });
对于上述的需求,可以这样写:
use crawler;
db.videos.group(
 {key:{siteId:true},
   reduce:function(obj,prev){ prev.count++;},
   initial:{count:0}
 });
现在说明一下:因为需求中没条件限制,所以cond域就不用写了。另外在reduce中,那个function函数可以提出外面写,如:
r = function(obj,prev){
  prev.count++};
db.videos.group(
 {key:{siteId:true},
   reduce: r,
   initial:{count:0}
 });
在mongoDB中,function()就相当于JavaScript的语法。
这里需要注意的是,在reduce的function函数中,一定要有两个参数(obj,prev),obj是当前遍历的对象,
prev是聚合计数器[aggregation counter obj]。
上述命令的结果显示是:
[
        {
                "siteId" : 1,
                "count" : 188603
        },
        {
                "siteId" : 3,
                "count" : 2198
        },
        {
                "siteId" : 2,
                "count" : 210
        }
]
通过MapReduce方法:
在mongo终端输入:
m = function () {
    emit(this.siteId, 1);
};
r = function (key, values) {
    var total = 0;
    for (var i = 0; i < values.length; i++) {
        total += values[i];
    }
    return total;
};
res = db.videos.mapReduce(m,r);
db[res.result].find();  //显示结果
上述的函数显示每个siteId的总记录数,结果如下:
{ "_id" : 1, "value" : 188603 }
{ "_id" : 2, "value" : 210 }
{ "_id" : 3, "value" : 2198 }
res = db.videos.mapReduce(m,r); 语句也可以这样写:
res = db.runCommand({
 mapreduce:"videos",
 map:m,
 reduce:r});
若忘记把db.runCommand()的结果传入res中,则可以在运行完runCommand命令的打印信息里找到 
"result" : "tmp.mr.mapreduce_1291273572_8",之类的信息,则表明结果保存在
tmp.mr.mapreduce_1291273572_8的表中,在终端直接写:
tmp.mr.mapreduce_1291273572_8.find()则会显示结果。
最后db[res.result].drop(),把最后结果删除。
Map函数中需要把emit()函数把结果传给reduce函数。emit(key,value)中,key是value作为分组的key,
value的类型需要和reduce函数的values的类型一致。Map函数在传给Reduce函数前,会合并相同key的value,
形成(key,values)的中间结果,并传给reduce函数。
Reduce函数中对中间结果进行处理,并把最后结果存入result中。
在mapReduce中可以添加条件,如db.videos.mapReduce(m,r[,option...]) 或根据官方文档的标准语法:
db.runCommand(
 { mapreduce : <collection>,
   map : <mapfunction>,
   reduce : <reducefunction>
   [, query : <query filter object>]
   [, sort : <sort the query.  useful for
 optimization>]
   [, limit : <number of objects to return
 from collection>]
   [, out : <output-collection name>]
   [, outType : ("normal"
|"merge"
|"reduce"
)] -- since 1.7.3
   [, keeptemp: <true
|false
>]
   [, finalize : <finalizefunction>]
   [, scope : <object where fields go into javascript global scope >]
   [, verbose : true
]
 }
);
 
版权声明:本文为yulchaochow原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
