浅谈一下MongoDB中的聚合

很多时候,从数据库中查出来的数据不一定满足我们的需求,需要进行再次二次加工,比如求和,分组,排序,分页等。这里就由此展开,说一下MongoDB中如何处理聚合,常用的聚合框架,和标准sql做类比

1. 先提一下,何为聚合
  • 概念和例子
    其实单纯说概念,有点绕,但实际上已经用了很多次了,比如mysql中我们对结果集进行再次加工,举例来说

    select avg(salary) as total,employeeNo from employee group by employeeNo;	
    

    上边的sql中,对原始的字段做了group、avg 的二次加工处理,实际上这就是聚合的简单应用。
    mongoDB,Nosql型数据库,也是引入了聚合(aggregate)的概念, 主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。

  • mongo中的聚合
    mongodb,有一些简单的聚合命令(shell中使用),也有一些聚合的框架,引入管道处理聚合,也可以使用工具,比如MapReduce

2. 接下来,看一下,MongoDB的聚合框架
  • 聚合框架用处
    聚合框架是MongoDB设计出来服务于聚合的。在MongoDB中有一些构件,它们可以创建一个管道(pipeline),用来对文档进行变换组合。

  • 什么是管道呢 :
    在linux中,是首次接触管道的概念,用于将当前命令,当做下次命令的参数。不过,在MongoDB中 聚合管道 是处理文档,将文档处理完成之后,传给下一个管道继续处理,管道操作可以重复

  • 常见的聚合操作,如下表

操作含义mongodb语法例子
projecting (投影)类比于标准sql中自定义查询字段,修改字段别名等。可以做到增加或删除域、重命名、创建计算结果和嵌套文档,修盖文档结构等{"$project":{“author”:1}}
grouping(分组)右边的例子,相当于是sql :select by_user, sum(*) as num_tutorial from mycol group by by_user{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : {$sum : 1}}}
sorting(排序)如右边的例子,对结果集按照count进行排序{"$sort":{“count”:-1}}
limiting(限制)限制MongoDB聚合管道返回的文档数{"$limit":5}
skiping(跳过)在聚合管道中跳过指定数量的文档,并返回余下的文档{ $skip : 5 }
  1. projecting : 投影
    “$project” 类似于sql中select的字段,可以自己制定返回的字段; 可以返回表达式; 可以重命名。所以这是非常强大的功能,比如下边几个例子
    //查询需要的字段
    db.peo.aggregate({"$project":{"author":1}}) 
    //返回结果 : objectid 省略了
    	{
    	   "result" : [
    	      {
    	         "_id" : objectId(),
    	         "author" :'lisi'
    	      },
    	      {
    	         "_id" : objectId(),
    	         "author" : 'zhangsan'
    	      }
    	   ],
    	   "ok" : 1
    	}
      // _id字段是默认返回的,如果不想要,可以用如下的语句
      db.peo.aggregate({"$project":{"author":1,"_id":0}})  
    
    上边展示了,"$project" 如何选择返回的字段,因为它返回的是一个文档列表,它可以制定那些字段需要,哪些不想要,因此,我把它理解为可以修改文档结构
    实际上,它的操作性很高,比如可以重命名字段,例如
    //重命名字段 : 下边把author字段重命名为authorMobile
      db.peo.aggregate({"$project":{"authorMobile":"$author"}})  
    
    需要注意一点,在以前的字段上建的索引,重命名后是无法使用的。很奇怪,命名还是一个字段。
    除了重命名、增删字段外,“$project”还可以返回表达式,如下
    db.peo.aggregate({"$project":{"totalPay":{"$add":["$salary":"$bonus"]}}})  
    //上边就是计算雇的员工实际开销 : 薪水+奖金 ,新建一个字段totalPay
    
    实际上,字段加减乘除都可以,此外也有一些时间函数、字符串函数,如下表
语法含义
{“$add”:[expr1,expr2…]}字段相加
{“$subtract”:[expr1,expr2]}expr1-expr2 : 减法
{“$multiply”:[expr1,expr2…]}字段相乘
{“$divide”:[expr1,expr2]}expr1/expr2 : 除法
{“$mod”:[expr1,expr2]}expr1%expr2 : 取余
{“$year”:"$colName"}仅可以对日期字段做日期函数操作
{“$substr”:[expr1,startoffset,numToReturn]}截取字符串,从startoffset开始,截取numToReturn位
{“$concat”:[expr1,expr2…exprN]}多个字符串拼接
{“$toLower”:expr}把字符串值变小写,大写(toUpper)用法同理
{“$con”:[booleanExpr,trueExpr,falseExpr]}条件判断,类似case when ,如果booleanExpr为真,返回trueExpr,否则返回falseExpr
{“$ifNull”:[expr,replaceExpr]}条件判断,如果expr为空,就返回replaceExpr

值得注意一点,这些条件都可以自由组合,以便于返回满足实际需要的字段

  1. group :分组
    效果类似于标准sql中的group, 可以利用选定的字段,完成聚合操作,如下
    {"$group":{"_id":"$day"}} //把day选做分组字段
    
    一般情况下,分组都是结合分组函数使用,才有实际意义,可以结合如下操作
     //计算每个国家的总收入
    {"$group":{"_id":"$country","totalRevenue":{"$sum":"$revenue"}}}
    //按照国家分组,相同国家的revenue进行求和,相当于下边的sql
    select sum(revenue) as totalRevenue form world group by country
    
    其他类似的函数 : “$max”,"$avg","$min","$last"等,原理类似,就不多说了
  2. 其他的一些构件
    基本上类似标准sql, 语法也很简单,比如
    {"$sort":{"name":1}} //按照name字段升序排列,降序是-1
    {"$limit":5} //限制返回的文档数为5
    {"$skip":6}//跳过前六条document
    
  • mongodb 调用这些管道操作
    上边整理了,mongodb常用的聚合管道,在实际调用的时候,只需要把这些管道操作传到aggregate函数即可,如下
    db.article.aggregate(
       { $project : {
           _id : 0 ,
           title : 1 ,
           author : 1
    }});
    
    mongoDB要求,使用管道之前,(比如 “$project”) 尽量先完成数据过滤
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值