9.聚合函数count+distinct+group + MapReduce

1.max最大值 min最小值

mongoDB不像SQL那样有min() 和max()函数。但是可以通过sort排序和limit限制返回来得到想要的结果

找到投票数helpful_votes**最多**的评论:(最大值,按照降序排列,并限制返回第1条记录)

db.reviews.find({}).sort({helpful_votes : -1}).limit(1)

找到投票数helpful_votes**最少**的评论:(最小值,按照升序排列,并限制返回第1条记录)

db.reviews.find({}).sort({helpful_votes : 1}).limit(1)

2.count()函数

请统计persons中美国学生的人数

> db.persons.find({country:"USA"}).count()
3

3.distinct()函数

查询persons中一共有多少个国家,分别是什么?

> db.persons.distinct("country")
[ "USA", "China", "Korea" ]

或者:

> db.runCommand({distinct:"persons",key:"country"}).values
[ "USA", "China", "Korea" ]

4.group()函数

语法:

db.runCommand({group:{
    ns:集合名称,
    key:分组的键对象,
    initial:初始化累加器,
    $reduce:组分解器,
    condition:条件,
    finalize:组完成器
}})

格式标准参照:

{
  group:
   {
     ns:<namespace> ,
     key:<key> ,
     $reduce:<reduce function> ,
     $keyf: <key function>,
     cond: <query>,
     finalize:<finalize function> 
   }
}

key:指定要分组的字段,可以使用复合键
keyf:为该文档生成一个临时键的JavaScript函数
initial:聚合结果初始值的
reduce:执行聚合函数的JavaScript函数
cond:过滤要聚合文档的查询选择器
finalize:在返回结果集前用于每个结果文档的JavaScript函数

分组首先会按照key进行分组,每组的每一个文档全要执行$reduce的方法,它接收2个参数,一个是组内本条记录,一个是累加器数据

4.1 请查出persons中每个国家学生数学成绩最好的学生信息(必须在90分以上)

db.runCommand({group:{
ns:"persons",   //操作集合:persons
key:{"country":true},    //操作的键:country initial:{m:0},      //初始化值:数学m:0
$reduce:function(doc,prev){   //组分解器:比较并保存m值较大的 if(doc.m > prev.m){   prev.m = doc.m;
prev.name = doc.name; prev.country = doc.country; }
}, condition:{m:{$gt:90}  //过滤条件:m值比90分大的留下
}
}})   

运行结果:

{
        "retval" : [
                {
                        "country" : "USA",
                        "m" : 96,
                        "name" : "jim"
                },
                {
                        "country" : "China",
                        "m" : 96,
                        "name" : "lisi"
                }
        ],
        "count" : 3,
        "keys" : 2,
        "ok" : 1
}

4.2 在4.1的基础上将个人信息组合起来,通过m进行输出

db.runCommand({group:{
ns:"persons",   
key:{"country":true},   
initial:{m:0},     
$reduce:function(doc,prev){  
if(doc.m > prev.m){       prev.m = doc.m;
prev.name = doc.name; prev.country = doc.country; }
}, condition:{m:{$gt:90} 
},
finalize:function(prev){      prev.m = prev.name+" Math scores "+prev.m 
}}})

运行结果:

{
        "retval" : [
                {
                        "country" : "USA",
                        "m" : "jim Math scores 96",
                        "name" : "jim"
                },
                {
                        "country" : "China",
                        "m" : "lisi Math scores 96",
                        "name" : "lisi"
                }
        ],
        "count" : 3,
        "keys" : 2,
        "ok" : 1
}

4.3用函数格式化分组的键

如果集合中出现键counrty和counTry同时存在,那分组有点麻烦,
这要如何解决呢?

$keyf:function(doc){                 
    return {country:doc.counTry}         
},….. 

我们做一个小测试:
插入一行数据:

db.persons.insert({
name:"USPCAT",
age:27,
email:"2145567457@qq.com",
c:89,m:100,e:67,
counTry:"China",
books:["JS","JAVA","EXTJS","MONGODB"]
})

注意这个文档的“国家”键中“t”是大写的!

我们再次查询:

db.runCommand({group:{
    ns:"persons",
    key:{"country":true},
    initial:{m:0},
    $reduce:function(doc,prev){
        if(doc.m > prev.m){
            prev.m = doc.m;
            prev.name = doc.name;
            prev.country = doc.country;
        }
    },
    finalize:function(prev){
        prev.m = prev.name+" Math scores "+prev.m
    },
    condition:{m:{$gt:90}}
}})

查询结果是这样的:

{
        "retval" : [
                {
                        "country" : "USA",
                        "m" : "jim Math scores 96",
                        "name" : "jim"
                },
                {
                        "country" : "China",
                        "m" : "lisi Math scores 96",
                        "name" : "lisi"
                },
                {
                        "country" : null,
                        "m" : "USPCAT Math scores 100",
                        "name" : "USPCAT"
                }
        ],
        "count" : 4,
        "keys" : 3,
        "ok" : 1
}

发现第三条数据的country值是null,这是因为数据结构的不规范造成的,解决问题如下:
我们将新增的counTry字段的值给country
增加$keyf选项:

$keyf:function(doc){
        if(doc.counTry){
            return {country:doc.counTry}
        }else{
            return {country:doc.country}
        }
    }

再次查询:

{
        "retval" : [
                {
                        "country" : "USA",
                        "m" : "jim Math scores 96",
                        "name" : "jim"
                },
                {
                        "country" : "China",
                        "m" : "USPCAT Math scores 100",
                        "name" : "USPCAT"
                }
        ],
        "count" : 4,
        "keys" : 2,
        "ok" : 1
}

5. map-reduce

Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。
MongoDB提供的Map-Reduce非常灵活,对于大规模数据分析也相当实用。

>db.collection.mapReduce(
   function() {emit(key,value);},  //map 函数
   function(key,values) {return reduceFunction},   //reduce 函数
   {
      out:collection,
      query: document,
      sort: document,
      limit: number
   }
)

这里写图片描述

使用 MapReduce 要实现两个函数: Map 函数和 Reduce 函数

Map 函数调用 emit(key, value), 遍历 collection 中所有的记录, 将key 与 value 传递给 Reduce 函数进行处理。
Map 函数必须调用 emit(key, value) 返回键值对。

参数说明:
• map :映射函数 (生成键值对序列,作为 reduce 函数参数)。
• reduce 统计函数,reduce函数的任务就是将key-values变成key-value,也就是把values数组变成一个单一的值value。。
• out 统计结果存放到集合 (不指定则使用临时集合,在客户端断开后自动删除)。
• query 一个筛选条件,只有满足条件的文档才会调用map函数。(query。limit,sort可以随意组合)
• sort 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制
• limit 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)

> db.posts.mapReduce(
...    function() { emit(this.user_name,1); },
...    function(key, values) {return Array.sum(values)},
...       {
...          query:{status:"active"},
...          out:"post_total"
...       }
... )
{
        "result" : "post_total",
        "timeMillis" : 214,
        "counts" : {
                "input" : 5,
                "emit" : 5,
                "reduce" : 1,
                "output" : 2
        },
        "ok" : 1,
}
> db.posts.mapReduce(
...    function() { emit(this.user_name,1); },
...    function(key, values) {return Array.sum(values)},
...       {
...          query:{status:"active"},
...          out:"post_total"
...       }
... ).find()

运行结果:
{ "_id" : "mark", "value" : 4 }
{ "_id" : "runoob", "value" : 1 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值