8.mongodb的聚合操作
8.1 mongodb的聚合是什么
聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。
语法:db.集合名称.aggregate( {管道:{表达式}} )
8.2 mongodb的常用管道和表达式
8.2.1 常用管道命令
在mongodb中,文档处理完毕后,通过管道进行下一次处理 常用管道命令如下:
- $group:将集合中的文档分组,可用于统计结果
- $match:过滤数据,只输出符合条件的文档
- $project:修改文档的结果,如重命名、增加、删除字段、创建计算结果
- $sort:将输入文档排序后输出
- $limit:限制聚合管道返回的文档数
- $skip:跳过指定数量的文档,并返回余下的文档
8.2.2 常用表达式
表达式:处理输入文档并输出 语法: 表达式:"$列名" 常用表达式:
- s u m : 计 算 综 合 , sum:计算综合, sum:计算综合,sum:1 表示以一倍计数
- $avg:计算平均值
- $min:获取最小值
- $max:获取最大值
- $push:在结果文档中插入值到一个数组中
8.3 管道命令之 $group
8.3.1 按照某个字段进行分组
$group是所有聚合命令中用的最多的一个命令,用来将集合中的文档分组,可用于统计结果
使用实例如下:
db.stu.aggregate(
{$group:
_id:"$gender",
counter:{$sum:1}
}
)
注意点:
- db.db_name.aggregate是语法,所有的管道命令都需要写在其中
- _id表示分组的依据,按照哪个字段进行分组,比如使用$gender表示选择这个字段进行分组
- $sum:1 表示把每条数据作为1进行统计,统计的是该分组下面的数据的条数
8.3.2 group by null
当我们需要统计整个文档的时候,$group的另一种用途就是把整个文档分为一组进行统计
使用实例如下:
db.stu.aggregate(
{$group:
{
_id:null,
counter:{$num:1}
}
}
)
注意点:
- _id:null表示不指定分组的字段,即统计整个文档,此时获取的counter表示整个文档的个数
8.3.3 数据透视
正常情况下在统计的不同性别的数据的时候,需要知道所有的name,需要逐条观察,如果通过某种方式把所有的name放到一起,那么此时就可以理解为数据透视。
使用实例如下:
#1.统计不同性别的学生
db.stu.aggregate(
{$group:
{
_id:null,
name:{$push:"$name"}
}
}
)
#2.使用$$ROOT可以将整个文档放入数组中
db.stu.aggregate(
{$group:
{
_id:null,
name:{$push:"$$ROOT"}
}
}
)
8.4管道命令之$match
m a t c h 用 于 进 行 数 据 的 过 滤 , 是 能 够 在 聚 合 操 作 中 使 用 的 命 令 , 和 f i n d 区 别 在 于 match用于进行数据的过滤,是能够在聚合操作中使用的命令,和find区别在于 match用于进行数据的过滤,是能够在聚合操作中使用的命令,和find区别在于match操纵可以把结果交给下一个管道处理,而find不行
使用实例如下:
#1.查询年龄大于20岁的学生
db.stu.aggregate(
{$match:{$age:{$gt:20}}}
)
#2.查询年龄大于20的男生和女生的人数
db.stu.aggregate(
{
$match:{$age:{$gt:20}}
{$group:{_id:"$gender"},counter:{$sum:1}}
}
)
8.5管道命令之$project
$project用于修改文档的输入输出结构,列入重命名,增加,删除字段
使用实例如下:
#1.查询学生的年龄、姓名,仅输出年龄姓名
db.stu.aggregate(
{$project:{_id:0,name:1,age:1}}
)
#2.查询男生女生的人数,只输出人数
db.stu.aggregate(
{$group:{_id:"$gender",counter:{$sum:1}}}
{$project:{_id:0,counter:1}}
)
8.6 管道命令之$sort
$sort用于将输入的文档排序后输出
使用实例如下:
#1.查询学生信息,按照年龄升序
db.stu.aggregate(
{$sort:{age:1}}
)
#2.查询男女生人生,按照人数降序
db.stu.aggregate(
{$group:{_id:"$gender",counter:{$sum:1}}}
{$sort:{counter:-1}}
)
8.7 管道命令之 l i m i t 和 limit和 limit和skip
- $limit 限制返回数据的条数
- $skip 跳过指定的文档书,并返回剩下的文档数
- 同时使用时先skip再使用limit
使用实例如下:
#1.查询2条学生信息
db.stu.aggregate(
{$limit:2}
)
#2.查询从第三条开始的数据
db.stu.aggregate(
{$skip:3}
)
#3.统计男女生人数,按照人数升序,返回第二条数据
db.stu.aggregate(
{$group:{_id:"$gender"},counter:{$sum:1}},
{$sort:{counter:1}},
{$skip:1},
{$limit:1}
)
8.8 拆分管道
db.stu.aggregate({$unwind:{path:"size",preserveNullAndEmptyArrays:true}})
按照size字段进行拆分数据
9.mongodb的索引
9.1 为什么mongodb需要创建索引
- 加快查询速度
- 进行数据的去重
9.2 mongodb创建简单的索引方法
- db.集合名称.ensureIndex( {属性:1} )
- 1表示升序,-1表示降序
9.3 创建索引前后查询速度对比
-
插入数据:
for(i=0;i<100000;i++) {db.t1.insert({name:"test"+i,age:i})}
-
创建索引前:
db.t1.find( {name:"test10000"} ) # 显示查询操作的详细信息 db.t1.find( {name:"test10000"} ).explain(executionStats"")
-
创建索引:
db.t1.ensureIndex({name:1})
-
创建索引后:
db.t1.find({name:"test10000"}).explain("executionStats")
9.4索引的查看
默认情况下_id是集合的索引 查看方式 :db.集合名称.getIndexes()
9.5删除索引
-
db.集合名称.dropIndex( {“索引名称”:1} )
db.t1.dropIndex({name:1}) db.t1.getIndexes()
9.6 mongodb创建唯一索引
在默认情况下mongodb的索引域的值是可以相同的,创建唯一索引后,数据库会在插入数据的时候检查创建索引域的值是否存在,如果存在则不会插入该条数据,但是创建索引仅仅能够提高查询速度,同时降低数据库的插入速度。
9.6.1 添加唯一索引的语法:
db.集合名称.ensureIndex({字段名:1},{unique:true})
9.6.2 利用唯一索引进行数据去重
根据唯一索引指定的字段的值,如果相同,则无法插入数据
db.t1.ensureIndex({name:1},{unique:true})
db.t1.insert({name:"test10000"})
9.7 mongodb创建复合索引
在进行数据去重的时候,可能用一个域来保证数据的唯一性,这个时候可以考虑建立复合索引来实现。
例如:抓全贴吧信息,如果把帖子的名字作为唯一索引对数据进行去重是不可取的,因为可能有很多帖子的名字相同。
建立复合索引的语法:
- db.集合名字.ensureIndex({字段1:1,字段2:1})
9.8 建立索引注意点
- 根据需要选择是否需要建立唯一索引
- 索引字段是升序还是降序在单个索引的情况下不影响查询效率,但是带复合索引的条件下会有影响
- 数据量巨大并且数据库的读出操作非常频繁的时候不需要创建索引,如果写入操作非常频繁,创建索引会影响写入速度。
- 例如:在进行查询的时候如果字段1需要升序的方式排序输出,字段2需要降序的方式排序输出,那么此时复合索引的建立需要把字段1设置为1,字段2设置为-1