MongoDB的聚合是什么意思

本篇内容介绍了“MongoDB的聚合是什么意思”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

新源ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为创新互联的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:028-86922220(备注:SSL证书合作)期待与您的合作!

MongoDB的产生背景是在大数据环境,所谓的大数据实际上就是信息的收集汇总。那么就必须存在信息的统计操作,而这样的统计操作就称为聚合(分组统计就是一种聚合操作)。

1、取得集合的数据量
对于集合的数据量而言,在MongoDB里面直接使用count()函数就可以完成了。
范例:统计emp表中的数据量
> db.emp.count();
8

范例:模糊查询
> db.emp.count({"name":/孙/i})
1


2、消除重复数据
在学习SQL的时候对于重复的数据可以使用“DISTINCE”,那么这一操作在MongoDB之中依然支持。
范例:查询所有name的信息
本次的操作没有直接的函数支持,只能够利用Command()指令。
> db.runCommand({"distinct":"emp","key":"name"})
{
        "values" : [
                "赵一",
                "钱二",
                "孙三",
                "李四",
                "周五",
                "吴六",
                "郑七",
                "王八"
        ],
        "ok" : 1
}

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


3、group操作
使用“group”操作可以实现数据的分组操作,在MongoDB里面会将集合依据指定的key进行分组操作。并且每一组都会产生一个处理的文档结果。
范例:查询所有年龄大于等于30岁的人员,并且按照年龄分组
> db.runCommand({"group":{
... "ns":"emp",
... "key":{"age":true},
... "initial":{"count":0},
... "condition":{"age":{"$gte":30}},
... "$reduce":function(doc,prev){prev.count++;}
... }})
{
        "retval" : [
                {
                        "age" : 30,
                        "count" : 4
                },
                {
                        "age" : 40,
                        "count" : 1
                },
                {
                        "age" : 50,
                        "count" : 1
                },
                {
                        "age" : 35,
                        "count" : 2
                }
        ],
        "count" : NumberLong(8),
        "keys" : NumberLong(4),
        "ok" : 1
}

以上的操作代码就属于一种MapReduce,很少这样写。这样只是根据传统的数据库的设计思路,实现了一个所谓的分组操作。但是这个分组操作最终结果是有限的。


4、MapReduce
MapReduce是整个大数据的精髓所在(实际中别用),所谓的MapReduce实际上就是分为两步处理数据:
  ● Map:将数据分别取出
  ● Reduce:负责数据的最后处理
可是要想在MongoDB里面实现MapReduce处理,那么复杂度是相当高的。

范例:创建一组人员数据
db.emps.insert({"name":"赵一","age":30,"sex":"女","job":"CLERK","sal":1000});
db.emps.insert({"name":"钱二","age":22,"sex":"男","job":"ACCOUNT","sal":2000});
db.emps.insert({"name":"孙三","age":28,"sex":"女","job":"CLERK","sal":3000});
db.emps.insert({"name":"李四","age":35,"sex":"女","job":"IT","sal":4000});
db.emps.insert({"name":"周五","age":31,"sex":"男","job":"SEC","sal":5000});
db.emps.insert({"name":"吴六","age":40,"sex":"女","job":"MANAGER","sal":6000});
db.emps.insert({"name":"郑七","age":44,"sex":"男","job":"CLERK","sal":1500});
db.emps.insert({"name":"王八","age":55,"sex":"男","job":"SAL","sal":5500});

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

范例:按照职位分组,取得每个职位的姓名
第一步:编写分组的定义:
var jobMapFun=function(){
emit(this.job,this.name);
}
第二步:编写Reduce操作:
> var jobReduceFun=function(key,values){
... return {"job":key,"name":values};
... }
第三步:针对于MapReduce处理完成的数据实际上也可以执行一个最后处理。
var jobFinalizeFun=function(key,values){
if(key=="MANAGER"){
return {"job":key,"name":values,"info":"公司老大"};}
return {"job":key,"name":values};
}
进行操作的整合:
db.runCommand({
"mapreduce":"emps",
"map":jobMapFun,
"reduce":jobReduceFun,
"out":"t_emps_job",
"finalize":jobFinalizeFun});
{
        "result" : "t_emps_job",
        "timeMillis" : 28,
        "counts" : {
                "input" : 8,
                "emit" : 8,
                "reduce" : 1,
                "output" : 6
        },
        "ok" : 1
}
现在执行之后,所有的处理结果都保存在了"t_emps_job"集合里面。
> db.t_emps_job.find();
{ "_id" : "ACCOUNT", "value" : { "job" : "ACCOUNT", "name" : "钱二" } }
{ "_id" : "CLERK", "value" : { "job" : "CLERK", "name" : { "job" : "CLERK", "name" : [ "赵一", "孙三", "郑七" ] } } }
{ "_id" : "IT", "value" : { "job" : "IT", "name" : "李四" } }
{ "_id" : "MANAGER", "value" : { "job" : "MANAGER", "name" : "吴六", "info" : "公司老大" } }
{ "_id" : "SAL", "value" : { "job" : "SAL", "name" : "王八" } }
{ "_id" : "SEC", "value" : { "job" : "SEC", "name" : "周五" } }

范例:统计出各性别的人数,平均工资,最低工资,雇员姓名
var sexMapFun=function(){
emit(this.sex,{"ccount":1,"csal":this.sal,"cmax":this.sal,"cmin":this.sal,"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 (maxmax=values[x].cmax; //找到最高工资
}
if (min>values[x].cmin){
min=values[x].cmin; //找到最低工资
}
names[x]=values[x].cname; //保存姓名
}
var avg=(sum/total).toFixed(2);
return {"count":total,"avg":avg,"max":max,"min":min,"name":names};
}; //返回数据处理结果

db.runCommand({
"mapreduce":"emps",
"map":sexMapFun,
"reduce":sexReduceFun,
"out":"t_emps_sex"
})
{
        "result" : "t_emps_sex",
        "timeMillis" : 31,
        "counts" : {
                "input" : 8,
                "emit" : 8,
                "reduce" : 2,
                "output" : 2
        },
        "ok" : 1
}

> db.t_emps_sex.find().pretty();
{
        "_id" : "女",
        "value" : {
                "count" : 4,
                "avg" : "3500.00",
                "max" : 6000,
                "min" : 1000,
                "name" : [
                        "赵一",
                        "孙三",
                        "李四",
                        "吴六"
                ]
        }
}
{
        "_id" : "男",
        "value" : {
                "count" : 4,
                "avg" : "3500.00",
                "max" : 5500,
                "min" : 1500,
                "name" : [
                        "钱二",
                        "周五",
                        "郑七",
                        "王八"
                ]
        }
}

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


5、聚合框架
MapReduce功能强大,但是复杂度太大,很多时候需要MapReduce功能,可是又不想把代码写得太复杂。所以在MongoDB 2.x版本之后开始引入了聚合框架并且提供了聚合函数:aggregate()。

5.1 $group
group主要进行分组的数据操作。
范例:实现聚合查询的功能--求出每个职位的人员数量
> db.emps.aggregate([{"$group":{"_id":"$job",job_count:{"$sum":1}}}])
{ "_id" : "MANAGER", "job_count" : 1 }
{ "_id" : "ACCOUNT", "job_count" : 1 }
{ "_id" : "IT", "job_count" : 1 }
{ "_id" : "SAL", "job_count" : 1 }
{ "_id" : "CLERK", "job_count" : 3 }
{ "_id" : "SEC", "job_count" : 1 }

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

范例:求出每个职位的总工资
> db.emps.aggregate([{"$group":{"_id":"$job",job_sal:{"$sum":"$sal"}}}])
{ "_id" : "MANAGER", "job_sal" : 6000 }
{ "_id" : "ACCOUNT", "job_sal" : 2000 }
{ "_id" : "IT", "job_sal" : 4000 }
{ "_id" : "SAL", "job_sal" : 5500 }
{ "_id" : "CLERK", "job_sal" : 5500 }
{ "_id" : "SEC", "job_sal" : 5000 }

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

范例:计算出每个职位的平均工资
> db.emps.aggregate([{"$group":{"_id":"$job","job_sal":{"$sum":"$sal"},"job_avg":{"$avg":"$sal"}}}])
{ "_id" : "MANAGER", "job_sal" : 6000, "job_avg" : 6000 }
{ "_id" : "ACCOUNT", "job_sal" : 2000, "job_avg" : 2000 }
{ "_id" : "IT", "job_sal" : 4000, "job_avg" : 4000 }
{ "_id" : "SAL", "job_sal" : 5500, "job_avg" : 5500 }
{ "_id" : "CLERK", "job_sal" : 5500, "job_avg" : 1833.3333333333333 }
{ "_id" : "SEC", "job_sal" : 5000, "job_avg" : 5000 }

范例:求出最高与最低工资
> db.emps.aggregate([{"$group":{"_id":"$job","max_sal":{"$max":"$sal"},"min_avg":{"$min":"$sal"}}}])
{ "_id" : "MANAGER", "max_sal" : 6000, "min_avg" : 6000 }
{ "_id" : "ACCOUNT", "max_sal" : 2000, "min_avg" : 2000 }
{ "_id" : "IT", "max_sal" : 4000, "min_avg" : 4000 }
{ "_id" : "SAL", "max_sal" : 5500, "min_avg" : 5500 }
{ "_id" : "CLERK", "max_sal" : 3000, "min_avg" : 1000 }
{ "_id" : "SEC", "max_sal" : 5000, "min_avg" : 5000 }

以上的几个与SQL类似的操作计算成功实现了。

范例:计算出每个职位的工资数据(数组显示)
> db.emps.aggregate([{"$group":{"_id":"$job","sal_data":{"$push":"$sal"}}}])
{ "_id" : "MANAGER", "sal_data" : [ 6000 ] }
{ "_id" : "ACCOUNT", "sal_data" : [ 2000 ] }
{ "_id" : "IT", "sal_data" : [ 4000 ] }
{ "_id" : "SAL", "sal_data" : [ 5500 ] }
{ "_id" : "CLERK", "sal_data" : [ 1000, 3000, 1500 ] }
{ "_id" : "SEC", "sal_data" : [ 5000 ] }

范例:求出每个职位的人员
> db.emps.aggregate([{"$group":{"_id":"$job","sal_data":{"$push":"$name"}}}])
{ "_id" : "MANAGER", "sal_data" : [ "吴六" ] }
{ "_id" : "ACCOUNT", "sal_data" : [ "钱二" ] }
{ "_id" : "IT", "sal_data" : [ "李四" ] }
{ "_id" : "SAL", "sal_data" : [ "王八" ] }
{ "_id" : "CLERK", "sal_data" : [ "赵一", "孙三", "郑七" ] }
{ "_id" : "SEC", "sal_data" : [ "周五" ] }

使用“$push”的确可以将数据变为数组进行保存,但是有一个问题出现了,重复的内容也会进行保存,那么在MongoDB里面提供有取消重复的设置。
> db.emps.insert({"name":"吴六","age":40,"sex":"女","job":"MANAGER","sal":6000});
WriteResult({ "nInserted" : 1 })
> db.emps.insert({"name":"郑七","age":44,"sex":"男","job":"CLERK","sal":1500});
WriteResult({ "nInserted" : 1 })
> db.emps.insert({"name":"王八","age":55,"sex":"男","job":"SAL","sal":5500});
WriteResult({ "nInserted" : 1 })

> db.emps.aggregate([{"$group":{"_id":"$job","sal_data":{"$push":"$name"}}}])
{ "_id" : "MANAGER", "sal_data" : [ "吴六", "吴六" ] }
{ "_id" : "ACCOUNT", "sal_data" : [ "钱二" ] }
{ "_id" : "IT", "sal_data" : [ "李四" ] }
{ "_id" : "SAL", "sal_data" : [ "王八", "王八" ] }
{ "_id" : "CLERK", "sal_data" : [ "赵一", "孙三", "郑七", "郑七" ] }
{ "_id" : "SEC", "sal_data" : [ "周五" ] }

范例:取消重复的数据
> db.emps.aggregate([{"$group":{"_id":"$job","sal_data":{"$addToSet":"$name"}}}])
{ "_id" : "MANAGER", "sal_data" : [ "吴六" ] }
{ "_id" : "ACCOUNT", "sal_data" : [ "钱二" ] }
{ "_id" : "IT", "sal_data" : [ "李四" ] }
{ "_id" : "SAL", "sal_data" : [ "王八" ] }
{ "_id" : "CLERK", "sal_data" : [ "郑七", "孙三", "赵一" ] }
{ "_id" : "SEC", "sal_data" : [ "周五" ] }

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

范例:保存第一个内容
> db.emps.aggregate([{"$group":{"_id":"$job","sal_data":{"$first":"$name"}}}])
{ "_id" : "MANAGER", "sal_data" : "吴六" }
{ "_id" : "ACCOUNT", "sal_data" : "钱二" }
{ "_id" : "IT", "sal_data" : "李四" }
{ "_id" : "SAL", "sal_data" : "王八" }
{ "_id" : "CLERK", "sal_data" : "赵一" }
{ "_id" : "SEC", "sal_data" : "周五" }

范例:保存最后一个内容
> db.emps.aggregate([{"$group":{"_id":"$job","sal_data":{"$last":"$name"}}}])
{ "_id" : "MANAGER", "sal_data" : "吴六" }
{ "_id" : "ACCOUNT", "sal_data" : "钱二" }
{ "_id" : "IT", "sal_data" : "李四" }
{ "_id" : "SAL", "sal_data" : "王八" }
{ "_id" : "CLERK", "sal_data" : "郑七" }
{ "_id" : "SEC", "sal_data" : "周五" }

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


5.2 $project
可以利用$project来控制数据列的显示规则,规则如下:
  ● 普通列({成员:1|true}):表示要显示的内容
  ● “_id”列({"_id":0|false}):表示“_id”列是否显示
  ● 条件过滤列({成员:表达式}):满足表达式之后的数据可以进行显示

范例:只显示name、job列,不显示_id列
> db.emps.aggregate([{"$project":{"_id":0,"name":1}}])
{ "name" : "赵一" }
{ "name" : "钱二" }
{ "name" : "孙三" }
{ "name" : "李四" }
{ "name" : "周五" }
{ "name" : "吴六" }
{ "name" : "郑七" }
{ "name" : "王八" }
{ "name" : "吴六" }
{ "name" : "郑七" }
{ "name" : "王八" }

此时只有设置进去的列才可以被显示出来,而其他的列不能被显示出来。实际上这就属于数据库的投影机制。
实际上在数据投影的过程里面也支持四则运算:加法("$add")、减法("$subtract")、乘法(“$mulitipy”)、除法(“”$devided)、求模("$mod")

范例:四则运算
> db.emps.aggregate([{"$project":{"_id":0,"name":1,"职位":"$job","sal":1}}])
{ "name" : "赵一", "sal" : 1000, "职位" : "CLERK" }
{ "name" : "钱二", "sal" : 2000, "职位" : "ACCOUNT" }
{ "name" : "孙三", "sal" : 3000, "职位" : "CLERK" }
{ "name" : "李四", "sal" : 4000, "职位" : "IT" }
{ "name" : "周五", "sal" : 5000, "职位" : "SEC" }
{ "name" : "吴六", "sal" : 6000, "职位" : "MANAGER" }
{ "name" : "郑七", "sal" : 1500, "职位" : "CLERK" }
{ "name" : "王八", "sal" : 5500, "职位" : "SAL" }
{ "name" : "吴六", "sal" : 6000, "职位" : "MANAGER" }
{ "name" : "郑七", "sal" : 1500, "职位" : "CLERK" }
{ "name" : "王八", "sal" : 5500, "职位" : "SAL" }

> db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1,"年薪":{"$multiply":["$sal",12]}}}])
{ "name" : "赵一", "job" : "CLERK", "年薪" : 12000 }
{ "name" : "钱二", "job" : "ACCOUNT", "年薪" : 24000 }
{ "name" : "孙三", "job" : "CLERK", "年薪" : 36000 }
{ "name" : "李四", "job" : "IT", "年薪" : 48000 }
{ "name" : "周五", "job" : "SEC", "年薪" : 60000 }
{ "name" : "吴六", "job" : "MANAGER", "年薪" : 72000 }
{ "name" : "郑七", "job" : "CLERK", "年薪" : 18000 }
{ "name" : "王八", "job" : "SAL", "年薪" : 66000 }
{ "name" : "吴六", "job" : "MANAGER", "年薪" : 72000 }
{ "name" : "郑七", "job" : "CLERK", "年薪" : 18000 }
{ "name" : "王八", "job" : "SAL", "年薪" : 66000 }

除了四则运算之外也支持如下的各种运算符:
  ● 关系运算:大小比较("$cmp")、等于("$eq")、大于("$gt")、大于等于("$gte")、小于("$lt")、小于等于("$lte")、不等于("$ne")、判断NULL("$ifNull"),这些操作返回的结果都是布尔型数据。
  ● 逻辑运算:与("$and")、或("$or")、非("$not")
  ● 字符串操作:连接("$concat")、截取("$substr")、转小写("$toLower")、转大小("$toUpper")、不区分大小写比较("$strcasecmp")

范例:找出所有薪水大于等于2000的人员姓名,职位和薪水
> db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1,"工资":"$sal","是否大于2000":{"$gte":["$sal",2000]}}}])
{ "name" : "赵一", "job" : "CLERK", "工资" : 1000, "是否大于2000" : false }
{ "name" : "钱二", "job" : "ACCOUNT", "工资" : 2000, "是否大于2000" : true }
{ "name" : "孙三", "job" : "CLERK", "工资" : 3000, "是否大于2000" : true }
{ "name" : "李四", "job" : "IT", "工资" : 4000, "是否大于2000" : true }
{ "name" : "周五", "job" : "SEC", "工资" : 5000, "是否大于2000" : true }
{ "name" : "吴六", "job" : "MANAGER", "工资" : 6000, "是否大于2000" : true }
{ "name" : "郑七", "job" : "CLERK", "工资" : 1500, "是否大于2000" : false }
{ "name" : "王八", "job" : "SAL", "工资" : 5500, "是否大于2000" : true }
{ "name" : "吴六", "job" : "MANAGER", "工资" : 6000, "是否大于2000" : true }
{ "name" : "郑七", "job" : "CLERK", "工资" : 1500, "是否大于2000" : false }
{ "name" : "王八", "job" : "SAL", "工资" : 5500, "是否大于2000" : true }

范例:查询职位是manager的信息
> db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1,"职位":"$job","job":{"$eq":["$job","MANAGER"]}}}])
{ "name" : "赵一", "job" : false, "职位" : "CLERK" }
{ "name" : "钱二", "job" : false, "职位" : "ACCOUNT" }
{ "name" : "孙三", "job" : false, "职位" : "CLERK" }
{ "name" : "李四", "job" : false, "职位" : "IT" }
{ "name" : "周五", "job" : false, "职位" : "SEC" }
{ "name" : "吴六", "job" : true, "职位" : "MANAGER" }
{ "name" : "郑七", "job" : false, "职位" : "CLERK" }
{ "name" : "王八", "job" : false, "职位" : "SAL" }
{ "name" : "吴六", "job" : true, "职位" : "MANAGER" }
{ "name" : "郑七", "job" : false, "职位" : "CLERK" }
{ "name" : "王八", "job" : false, "职位" : "SAL" }

> db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1,"职位":"$job","job":{"$eq":["$job",{"$toUpper":"manager"}]}}}])
{ "name" : "赵一", "job" : false, "职位" : "CLERK" }
{ "name" : "钱二", "job" : false, "职位" : "ACCOUNT" }
{ "name" : "孙三", "job" : false, "职位" : "CLERK" }
{ "name" : "李四", "job" : false, "职位" : "IT" }
{ "name" : "周五", "job" : false, "职位" : "SEC" }
{ "name" : "吴六", "job" : true, "职位" : "MANAGER" }
{ "name" : "郑七", "job" : false, "职位" : "CLERK" }
{ "name" : "王八", "job" : false, "职位" : "SAL" }
{ "name" : "吴六", "job" : true, "职位" : "MANAGER" }
{ "name" : "郑七", "job" : false, "职位" : "CLERK" }
{ "name" : "王八", "job" : false, "职位" : "SAL" }

> db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1,"职位":"$job","job":{"$strcasecmp":["$job","manager"]}}}])
{ "name" : "赵一", "job" : -1, "职位" : "CLERK" }
{ "name" : "钱二", "job" : -1, "职位" : "ACCOUNT" }
{ "name" : "孙三", "job" : -1, "职位" : "CLERK" }
{ "name" : "李四", "job" : -1, "职位" : "IT" }
{ "name" : "周五", "job" : 1, "职位" : "SEC" }
{ "name" : "吴六", "job" : 0, "职位" : "MANAGER" }
{ "name" : "郑七", "job" : -1, "职位" : "CLERK" }
{ "name" : "王八", "job" : 1, "职位" : "SAL" }
{ "name" : "吴六", "job" : 0, "职位" : "MANAGER" }
{ "name" : "郑七", "job" : -1, "职位" : "CLERK" }
{ "name" : "王八", "job" : 1, "职位" : "SAL" }

范例:使用字符串截取
> db.emps.aggregate([{"$project":{"_id":0,"name":1,"job":1,"职位":"$job","job":{"前面三位":{"$substr":["$job",0,3]}}}}])
{ "name" : "赵一", "job" : { "前面三位" : "CLE" }, "职位" : "CLERK" }
{ "name" : "钱二", "job" : { "前面三位" : "ACC" }, "职位" : "ACCOUNT" }
{ "name" : "孙三", "job" : { "前面三位" : "CLE" }, "职位" : "CLERK" }
{ "name" : "李四", "job" : { "前面三位" : "IT" }, "职位" : "IT" }
{ "name" : "周五", "job" : { "前面三位" : "SEC" }, "职位" : "SEC" }
{ "name" : "吴六", "job" : { "前面三位" : "MAN" }, "职位" : "MANAGER" }
{ "name" : "郑七", "job" : { "前面三位" : "CLE" }, "职位" : "CLERK" }
{ "name" : "王八", "job" : { "前面三位" : "SAL" }, "职位" : "SAL" }
{ "name" : "吴六", "job" : { "前面三位" : "MAN" }, "职位" : "MANAGER" }
{ "name" : "郑七", "job" : { "前面三位" : "CLE" }, "职位" : "CLERK" }
{ "name" : "王八", "job" : { "前面三位" : "SAL" }, "职位" : "SAL" }

利用"$project"实现的投影操作功能相当强大,所有可能出现的操作几乎都能够使用。


5.3、$sort
使用"$sort"可以实现排序,设置1表示升序,设置-1表示降序。
范例:实现排序
> db.emps.aggregate([{"$project":{"_id":0,"age":1,"sal":1}},{"$sort":{"age":-1,"sal":1}}])
{ "age" : 55, "sal" : 5500 }
{ "age" : 55, "sal" : 5500 }
{ "age" : 44, "sal" : 1500 }
{ "age" : 44, "sal" : 1500 }
{ "age" : 40, "sal" : 6000 }
{ "age" : 40, "sal" : 6000 }
{ "age" : 35, "sal" : 4000 }
{ "age" : 31, "sal" : 5000 }
{ "age" : 30, "sal" : 1000 }
{ "age" : 28, "sal" : 3000 }
{ "age" : 22, "sal" : 2000 }

> db.emps.aggregate([{"$match":{"sal":{"$gte":3000,"$lte":5000}}},{"$project":{"_id":0,"age":1,"sal":1}},{"$sort":{"age":-1,"sal":1}}])
{ "age" : 35, "sal" : 4000 }
{ "age" : 31, "sal" : 5000 }
{ "age" : 28, "sal" : 3000 }

> db.emps.aggregate([
... {"$match":{"sal":{"$gte":3000,"$lte":6000}}},
... {"$project":{"_id":0,"age":1,"sal":1}},
... {"$group":{"_id":"$age","count":{"$sum":1}}},
... {"$sort":{"count":-1}}])
{ "_id" : 55, "count" : 2 }
{ "_id" : 40, "count" : 2 }
{ "_id" : 28, "count" : 1 }
{ "_id" : 35, "count" : 1 }
{ "_id" : 31, "count" : 1 }

> db.emps.aggregate([
... {"$match":{"sal":{"$gte":3000,"$lte":6000}}},
... {"$project":{"_id":0,"name":1,"sal":1,"job":1}},
... {"$group":{"_id":"$job","count":{"$sum":1},"avg":{"$avg":"$sal"}}},
... {"$sort":{"count":-1}}])
{ "_id" : "SAL", "count" : 2, "avg" : 5500 }
{ "_id" : "MANAGER", "count" : 2, "avg" : 6000 }
{ "_id" : "IT", "count" : 1, "avg" : 4000 }
{ "_id" : "CLERK", "count" : 1, "avg" : 3000 }
{ "_id" : "SEC", "count" : 1, "avg" : 5000 }

5.4、分页处理:$limit、$skip
"$limit":数据取出个数
“$skip”:数据跨过个数
范例:使用“$limit”设置取出个数
> db.emps.aggregate([
... {"$project":{"_id":0,"name":1,"sal":1}},
... {"$limit":2}
... ])
{ "name" : "赵一", "sal" : 1000 }
{ "name" : "钱二", "sal" : 2000 }

范例:跨过3行数据
> db.emps.aggregate([
... {"$project":{"_id":0,"name":1,"sal":1}},
... {"$skip":3},
... {"$limit":2}
... ])
{ "name" : "李四", "sal" : 4000 }
{ "name" : "周五", "sal" : 5000 }

> db.emps.aggregate([
... {"$match":{"sal":{"$gte":3000,"$lte":6000}}},
... {"$project":{"_id":0,"name":1,"sal":1,"job":1}},
... {"$group":{"_id":"$job","count":{"$sum":1},"avg":{"$avg":"$sal"}}},
... {"$sort":{"count":-1}},
... {"$skip":3},
... {"$limit":2}
... ])
{ "_id" : "IT", "count" : 1, "avg" : 4000 }
{ "_id" : "CLERK", "count" : 1, "avg" : 3000 }


5.5 $unwind
在查询数据的时候经常会返回数组信息,但是数组并不方便信息的浏览,所以提供有"$unwind"可以将数组数据变为对立的字符串内容。
范例:添加一些信息
db.depts.insert({"title":"技术部","busi":["研发","生产","培训"]});
db.depts.insert({"title":"技术部","busi":["薪酬","税务"]});

范例:将信息进行转化
> db.depts.aggregate([
... {"$project":{"_id":0,"title":1,"busi":1}},
... {"$unwind":"$busi"}
... ]);
{ "title" : "技术部", "busi" : "研发" }
{ "title" : "技术部", "busi" : "生产" }
{ "title" : "技术部", "busi" : "培训" }
{ "title" : "技术部", "busi" : "薪酬" }
{ "title" : "技术部", "busi" : "税务" }

此时相当于将数组的数据变为了单行的数据。

5.6 $geoNear
使用"$geoNear"可以得到附件的坐标点。
范例:准备测试数据
db.shop.drop();
db.shop.insert({loc:[10,10]});
db.shop.insert({loc:[20,10]});
db.shop.insert({loc:[10,20]});
db.shop.insert({loc:[20,20]});
db.shop.insert({loc:[100,100]});
db.shop.insert({loc:[80,30]});
db.shop.insert({loc:[30,50]});
db.shop.createIndex({"loc":"2d"})

范例:设置查询
> db.shop.aggregate([
... {"$geoNear":{"near":[30,30],"distanceField":"loc","maxDistance":20,"num":2}}
... ])
{ "_id" : ObjectId("5994ff7c0184ff511bf02bdc"), "loc" : 14.142135623730951 }
{ "_id" : ObjectId("5994ff7d0184ff511bf02bdf"), "loc" : 20 }

地理信息的检索必须存在索引的支持。


5.7 $out
"$out"可以将查询结果输出到指定的集合里面。
范例:将投影的结果输出到集合里
> db.emps.aggregate([
... {"$project":{"_id":0,"name":1,"sal":1}},
... {"$out":"emps_infos"}
... ])
> db.emps_infos.find();
{ "_id" : ObjectId("599501eeca6455d4a46874e0"), "name" : "赵一", "sal" : 1000 }
{ "_id" : ObjectId("599501eeca6455d4a46874e1"), "name" : "钱二", "sal" : 2000 }
{ "_id" : ObjectId("599501eeca6455d4a46874e2"), "name" : "孙三", "sal" : 3000 }
{ "_id" : ObjectId("599501eeca6455d4a46874e3"), "name" : "李四", "sal" : 4000 }
{ "_id" : ObjectId("599501eeca6455d4a46874e4"), "name" : "周五", "sal" : 5000 }
{ "_id" : ObjectId("599501eeca6455d4a46874e5"), "name" : "吴六", "sal" : 6000 }
{ "_id" : ObjectId("599501eeca6455d4a46874e6"), "name" : "郑七", "sal" : 1500 }
{ "_id" : ObjectId("599501eeca6455d4a46874e7"), "name" : "王八", "sal" : 5500 }
{ "_id" : ObjectId("599501eeca6455d4a46874e8"), "name" : "吴六", "sal" : 6000 }
{ "_id" : ObjectId("599501eeca6455d4a46874e9"), "name" : "郑七", "sal" : 1500 }
{ "_id" : ObjectId("599501eeca6455d4a46874ea"), "name" : "王八", "sal" : 5500 }

相当于实现了数据表的复制操作。

“MongoDB的聚合是什么意思”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注创新互联网站,小编将为大家输出更多高质量的实用文章!


分享标题:MongoDB的聚合是什么意思
转载注明:http://azwzsj.com/article/godjjo.html