MongoDB聚合(重点)

一、取得集合的数据量

范例:统计students表中的数据量

db.students.count();

范例:模糊查询

db.students.count({"name":/xie/i});

在进行数据查询的时候,不设置条件永远要比设置条件的查询快很多,也就是说在之前的代码编写里面不管是查询全部还是模糊查询,实际上最终都是使用的模糊查询一种(只是没有设置关键字)。

二、消除重复数据(此功能意义不大)

范例:查询所有name的信息

本次的操作没有直接的函数支持,只能够利用runCommand()函数。

db.runCommand({"distinct":"students1","key":"name"});

此时实现了对于name数据的重复值的筛选。

MongoDB聚合(重点)_第1张图片

三、group操作

使用“group”操作可以实现数据的分组操作,在MongoDB里会将集合一句指定的key的不同进行分组操作,并且每一个组都会产生一个处理的文档结果。

范例:查询所有年龄大于等于19岁的学生信息,并且按照年龄分组

db.runCommand({"group":{"ns":"students","key":{"age":true},"initial":{"count":0},"condition":{"age":{"$gte":19}},"$reduce":function(doc,prev){

prev.count++;//表示数量加一

}

}});

以上的操作代码就属于一种MapReduce

MongoDB聚合(重点)_第2张图片

四、MapReduce

MapReduce是整个大数据的精髓所在(实际中别用),所谓的MapReduce就是分位两步处理数据:

Map:将数据分别取出;

Reduce:负责数据的最后的处理;

可是要想在MongoDB里实现MapReduce处理,那么复杂度是相当高的。

范例:建立一组雇员数据

db.emps.insert({"name":"张三","age":30,"sex":"男","job":"CLERK","salary":1000});

db.emps.insert({"name":"李四","age":28,"sex":"女","job":"CLERK","salary":5000});

db.emps.insert({"name":"王五","age":26,"sex":"男","job":"MANAGER","salary":6000});

db.emps.insert({"name":"赵六","age":32,"sex":"女","job":"MANAGER","salary":7000});

db.emps.insert({"name":"孙七","age":31,"sex":"男","job":"CLERK","salary":2000});

db.emps.insert({"name":"王八","age":35,"sex":"女","job":"PRESIDENT","salary":9000});

使用MapReduce操作最终会将处理结果保存在一个单独的集合里面,而最终处理效果如下

范例:按照职位分组,取得每个职位的人名

第一步:编写分组的定义

var jobMapFun=function(){

emit(this.job,this.name);//按照job分组,取出name

};

//结果是:{key:"CLERK",values:[姓名,姓名,...]}

//第二步:编写reduce操作

var jobReduceFun=function(key,values){

return {"job":key,"names":values};

};

//第三步:针对于MapReduce处理完成的数据实际上也可以执行一个最后处理。

var jobFinalizeFun=function(key,values){

        if(key=="PRESIDENT"){

           return{"job":key,"names":values,"info":"公司的老大"};

         }

           return{"job":key,"names":values};

}

//第四步:进行操作的整合

db.runCommand({

"mapreduce":"emps",

"map":jobMapFun,

"reduce":jobReduceFun,

"out":"t_job_emp",

"finalize":jobFinalizeFun

});

 

现在执行上面三步之后,所有的处理结果都保存在了t_job_emp集合中了。

db.t_job.emp.find().pretty();

范例:统计出各性别的人数、平均工资、最低工资、雇员姓名

var sexMapFun=function(){

        //定义好了分组的条件,以及每个集合要取出的内容

        emit(this.sex,{"ccount":1,"csal":this.salary,"cmax":this.salary,"cmin":this.salary,"cname":this.name});

};

 

var sexReduceFun=function(key,values){

            var total=0;//统计

            var sum=0;//计算总工资

            var max=values[0].cmax;//假设第一个数据是最高工资

            var min=values[0].cmin;//假设第一个数据是最低工资

            var names=new Array();//定义数组内容

            for(var x in values){//表示循环取出里面的数据

                total+=values[x].ccount;//人数增加

                sum+=values[x].csal;//循环取出所有的工资,并且累加

                if(max

                      max=values[x].cmax;

                }

                if(min

                      min=values[x].cmin;

                }

                 names[x]=values[x].cname;//保存姓名

             }

            var avg=(sum/total).toFixed(2);//设置2位小数

            //返回数据的处理结果

            return {"count":total,"avg":avg,"sum" :sum,"max":max,"min":min,"names":names};

};

db.runCommand({

"mapreduce":"emps",

"map":sexMapFun,

"reduce":sexReduceFun,

"out": "t_sex_emp"});

结果如下:

MongoDB聚合(重点)_第3张图片

虽然提供有最强悍的MapReduce支持,但是从现实的开发来将,真的不可能使用起来。

五、聚合框架(核心

Mapreduce功能强大,但是它的复杂度和功能一样强大,那么很多时候我们需要MapReduce的功能,可是又不想把代码写的太复杂,所以从Mongo2.下版本之后开始引入了聚合框架并且提供了聚合函数:aggregate()

1,&group

group主要进行分组操作

范例:实现聚合查询的功能--求出每个职位的雇员人数

db .emps.aggregate([{"$group":{"_id":"$job","job_count":{"$sum":1}}}]);

这样的操作更加符合传统的group by子句的操作使用。

范例:求出每个职位的总工资

db .emps.aggregate([{"$group":{"_id":"$job","job_sal":{"$sum":"$salary"}}}]);

在整个聚合框架里面如果要引用每行的数据使用"$字段名称"。

范例:计算出每个职位的平均工资

db .emps.aggregate([{"$group":{

"_id":"$job",

"job_sal":{"$sum":"$salary"},

"job_avg":{"$avg":"$salary"}

}}]);

MongoDB聚合(重点)_第4张图片

范例:求出最高与最低工资

db .emps.aggregate([{"$group":{"_id":"$job","max_sal":{"$max":"$salary"},"min_sal":{"$min":"$salary"}}}]);

范例:计算出每个职位的工资数据(数组显示)

db.emps.aggregate([{"$group":{

"_id":"$job",

"sal_data":{"$push":"$salary"}}}]);

MongoDB聚合(重点)_第5张图片

范例:求出每个职位的人员

db.emps.aggregate([{"$group":{

"_id":"$job",

"sal_data":{"$push":"$name"}}}]);

MongoDB聚合(重点)_第6张图片

使用“$push“的确可以将数据变为数组进行保存,但是有一个问题也出现了,重复的内容也会进行保存,那么在MongoDB里面提供了取消重复的设置

范例:求出每个职位的人员(取消重复数据)

db.emps.aggregate([{"$group":{

"_id":"$job",

"sal_data":{"$addToSet":"$name"}}}]);

MongoDB聚合(重点)_第7张图片

默认情况下是将所有的数据都保存进去了,但是现在只希望可以保留第一个或者最后一个

范例:保存第一个内容(无序)

db.emps.aggregate([{"$group":{

"_id":"$job",

"sal_data":{"$first":"$name"}}}]);

MongoDB聚合(重点)_第8张图片

范例:保存最后一个内容(无序)

db.emps.aggregate([{"$group":{

"_id":"$job",

"sal_data":{"$last":"$name"}}}]);

MongoDB聚合(重点)_第9张图片

虽然可以方便的实现分组处理,但是有一点需要注意,所有的分组数据都是无序的,并且都是在内存中完成,所以不可能支持大数据量。

2,&project

可以利用“$project"来控制数据列的显示规则,那么可以执行的规则如下:

|-普通列({成员:1|true}):表示要显示的内容;

|-"_id"列({"_id":0|false}):表示“_id“列是否显示;

|-条件过滤列({成员:表达式})满足表达式之后的数据可以进行显示。

范例:只显示name、job列,不显示“_id”列

db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1}}]);

MongoDB聚合(重点)_第10张图片

 此时,只有设置进去的列才可以被显示出来,而其它的列不能够被显示出来。实际上这就是属于数据库的投影机制。

实际上在进行数据投影的过程里面也支持四则运算:加法(“$add")、减法(“$subtract)、乘法(“$multiply”)、除法(“$divide“)、求模($mod)。

范例:起一个别名

db.emps.aggregate([{"$project":{"_id":0,"name":1,"职位":"$job"}}]);

MongoDB聚合(重点)_第11张图片

范例:四则运算(求年薪)

db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1,"salary":{"年薪":{"$multiply":["$salary",12]}}}}]);

MongoDB聚合(重点)_第12张图片

除了四则运算之外,也支持如下的各种运算符:

关系运算:大小比较(“$cmp")、等于(”$eq“)、大于(”$gt“)、大于等于(“$gte”)、小于(“$lt”)、小于等于(“$lte”)、不等于(“$ne”)、判断NULL(“$ifNull”),这些返回值都是布尔数据。

逻辑运算:与(“$and”)、或(“$or”)、非(“$not”);

字符串操作:连接(“$concat”)、截取(“$substr”)、转小写(“$toLower”)、转大写(“$tpUpper”)、不区分大小写比较(“$strcasecmp”)。

范例:找出所有工资大于等于2000的雇员姓名、年龄、工资

db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1,"工资":"$salary","salary":{"$gte":["$salary",2000]}}}]);

MongoDB聚合(重点)_第13张图片

范例:查询职位是manager的信息

MongoDB中的数据是区分大小写的。

db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1,"职位":"$job","job":{"$eq":["$job","MANAGER"]}}}]);

MongoDB聚合(重点)_第14张图片

范例:查询职位是manager的信息(转化成大写查询)

db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1,"职位":"$job","job":{"$eq":["$job",{"$toUpper":"manager"}]}}}]);

范例:使用字符串截取

db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1,"职位":"$job","job":{"前三位":{"$substr":["$job",0,3]}}}}]);

MongoDB聚合(重点)_第15张图片

3,$sort

使用“$sort”可以实现排序,设置1表示升序,设置-1表示降序。

范例:实现排序

db.emps.aggregate([{"$sort":{"age":-1,"salary":1}}]);

4,分页处理:$limit、$skip

"$limit":负责数据的取出个数

"$skip":数据的跨过个数

范例:使用”$limit“设置取出的个数

db.emps.aggregate([

{"$project":{"_id":0,"name":1,"salary":1,"job":1}},

{"$limit":2}

]);

范例:使用”$limit“设置取出的个数,跨过3行

db.emps.aggregate([

{"$project":{"_id":0,"name":1,"salary":1,"job":1}},

{"$skip":3},

{"$limit":2}

]);

MongoDB聚合(重点)_第16张图片

5,$unwind

在查询数据的时候经常回返回数组信息,但是数组并不方便信息的浏览,所以提供有”$unwind“可以将数组数据变为独立的字符串内容。

范例:添加一些信息

db.depts.insert({"title":"技术部","bus":["研发","生产","培训"]});

db.depts.insert({"title":"财务部","bus":["工资","税收"]});

范例:将信息进行转化

db.depts.aggregate([

{"$project":{"_id":0,"title":true,"bus":true}},

{"$unwind":"$bus"}]);

MongoDB聚合(重点)_第17张图片

6,$geoNear(了解)

使用”$geoNear“可以得到附近的坐标点

范例:准备测试数据

db.shop.drop();

db.shop.insert({loc:[10,10]});

db.shop.insert({loc:[11,10]});

db.shop.insert({loc:[10,11]});

db.shop.insert({loc:[12,15]});

db.shop.insert({loc:[16,17]});

db.shop.insert({loc:[90,90]});

db.shop.insert({loc:[120,130]});

db.shop.ensureIndex({"loc":"2d"});//必须加索引,下面的查询命令才可以执行

范例:设置查询

db.shop.aggregate([

{"$geoNear":{

"near":[11,12],

"distanceField":"loc",

"maxDistance":1,

"num":2,

"spherical":true}}]);

MongoDB聚合(重点)_第18张图片

地理信息的检索必须存在有索引的支持,所以使用最原始的地理信息比较方便,这里getNear作为了解

7,$out

"$out":利用此操作可以将查询结果输出到指定的集合里面。

范例:将投影的结果输出到集合里(_id会重新编号)

db.emps.aggregate([

{"$project":{"_id":0,"name":1,"salary":1,"job":1}},

{"$out":"emp_infos"}

]);

MongoDB聚合(重点)_第19张图片

 这类的操作就相当于实现了最早的数据表的复制操作。

六、深入操作

1,固定集合

所谓的固定集合指的是规定集合大小,如果要保存的内容已经超过了集合的长度,那么会采用LRU的算法(最近最少使用的原则),将最早的数据移除,从而保存新的数据。

默认情况下一个集合可以使用createCollection()函数创建,或者使用增加数据后自动创建,但是如果要想使用固定的集合,就必须明确的创建一个空集合。

范例:创建一个空集合(固定集合)

db.createCollection("depts",{"capped":true,"size":1024,"max":5});

capped为true表示一个固定集合,而”size:1024“指的是集合所占的空间容量(字节),max等于5表示最多只能够有5条记录。

如果超过5条再插入,最早插入的会消失,实际上跟缓存机制的非常相似的,例如百度里的关键词(热门词),这些词都是会被不断替换的。

2,GridFS

在MongoDB里面支持大数据的存储(如图片、音乐等)

3,用户管理

在MongoDB里面默认情况下只要是进行连接都可以不使用用户名和密码,因为要想让其起作用,则必须具备以下条件:

条件一:服务器启动的时候打开授权认证;

条件二:需要配置用户名和密码。

但是需要明确的是,如果要想配置用户名和密码一定是针对于一个数据库的,例如现在要创建的mldn,数据库的用户,那么必须先切换到mldn数据库上。

use mldn;

范例:执行用户的创建(hello、java)

任何的用户都必须具备有一个自己的操作角色,对于角色最基础的角色:read、readWrite。

db.createUser({

"user":"hello",

"pwd":"java",

"roles":[{"role":"readWrite","db":"mldn"}]});

MongoDB聚合(重点)_第20张图片

表示已经成功创建了hello用户,那么要想让用户名起作用,必须以授权的方式打开MongoDB的服务,修改MongoDB的启动文件。

MongoDB聚合(重点)_第21张图片

noauth改为auth

这时候在使用集合的时候出现错误

MongoDB聚合(重点)_第22张图片

使用密码登陆

mongo localhost:34560/mldn -u hello -p java

MongoDB聚合(重点)_第23张图片

范例:修改密码

db.changeUserPassword("hello","happy");

如果要修改密码,那么就请关闭授权登陆

 

你可能感兴趣的:(MongoDB)