Java MongoDB:(十六)MongoDB 的文档操作-MongoDB 聚合查询-7100字匠心出品
分类:
文章
•
2022-10-05 11:14:14
MongoDB 的文档操作-MongoDB 聚合查询
- 在 MongoDB 中我们可以通过 aggregate()函数来完成一些聚合查询,aggregate()函数主要用于处理诸如统计,平均值,求和等,并返回计算后的数据结果
- 语法格式:
db.COLLECTION_NAME.aggregate([{$ group:{_id:"$ 分组键名","$ 分组键名",…,别名:{聚合运算:"$运算列"}}},{条件筛选:{键名:{运算条件:运算值}}}])
- 常见的 mongo 的聚合操作和 mysql 的查询做类比
1.求和 - $sum
- 查询 dev 集合中一共有多少个文档。
- 相当于 sql 语句:SELECT count(*) AS count FROM dev
- db.dev.aggregate([{$ group:{_id:null,count:{$sum:1}}}])
- $group:分组,代表聚合的分组条件
- _id:分组的字段。相当于 SQL 分组语法 group by column_name 中的 column_name 部分。如果根据某字段的值分组,则定义为_id:’$字段名’。所以此案例中的 null 代表一个固定的字面值’null’。
- count:返回结果字段名。可以自定义,类似 SQL 中的字段别名
- $sum:求和表达式。相当于 SQL 中的 sum()
- 1:累加值。
- 查询 dev 集合中的所有 size 键中的值的总和
- 相当于 sql 语句:SELECT sum(size) AS totalSize FROM dev
- db.dev.aggregate([{$ group:{_id:null,totalSize:{$ sum:"$size"}}}])
- “$size”:代表文档中的 szie 字段的值。
- 对每一个 title 进行分组并计算每组中的 size 的总和
- 相当于 sql 语句:SELECT title AS _id , sum(size) AS totalSize FROM dev GROUP BY title
- db.dev.aggregate([{$ group:{_id:"$ title",totalSize:{$ sum:"$size"}}}])
2.条件筛选 - $match
- 查询 dev 集合有多少文档的 size 大于 200
- db.dev.aggregate([{$ match:{size:{$ gt:200}}},{$ group:{_id:null,totalSize:{$sum:1}}}])
- 相当于 SQL 语句:SELECT count(*) FROM dev WHERE size > 200
- $match:匹配条件,相当于 SQL 中的 where 子句,代表聚合之前进行条件筛选
- 查询 dev 集合,根据 title 分组计算出每组的 size 的总和,并过滤掉总和小于等于 200的文档。
- db.dev.aggregate([{$ group:{_id:"$ title",totalSize:{$ sum:"$ size"}}},{$ match:{totalSize:{$gt:200}}}])
- 相当于 SQL 语句:SELECT sum(size) AS totalSize FROM dev GROUP BY title HAVING totalSize > 200
3.最大值 - $max
- 查询 dev 集合中 size 最大的文档
- db.dev.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …:null,maxSize:{max:"$size"}}}])
- $ max:"$size":计算 size 键中的最大值。
- 相当于 SQL 语句:SELECT max(size) FROM dev
4.最小值 - $min
- 查询 dev 集合中 size 最小的文档。
- db.dev.aggregate([{$ group:{_id:null,minSize:{$ min:"$size"}}}])
- $ min:"$size":计算 size 键中的最小值。
- 相当于 SQL 语句:SELECT min(size) FROM dev
5.平均值 - $avg
- 查询 dev 集合中 size 的平均值
- db.dev.aggregate([{$ group:{_id:null,sizeAvg:{$ avg:"$size"}}}])
- $ avg:"$size":计算 size 键的平均值
- 相当于 SQL 语句:SELECT avg(size) FROM dev
6.统计结果返回数组 - $push
- 查询 dev 集合,按照 size 分组并返回他们的 title,如果 size 相同则使用数组返回他们的title。
- db.dev.aggregate([{$ group:{_id:"$ size",title:{$ push:"$title"}}}])
- $ push:"$title":如果 size 相同则使用数组返回他们不同的 title
7.数组字段拆分 - $unwind
- 查询 dev 集合,将数组中的内容拆分显示
- db.dev.aggregate([{$ unwind:"$tags"}])
- $ unwind:"$tags":对数组中的元素进行拆分显示
8.管道操作
- 什么是管道操作:
- 管道在 Unix 和 Linux 中一般用于将当前命令的输出结果作为下一个命令的参数
- MongoDB 的聚合管道将 MongoDB 文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的
- 管道操作符是按照书写的顺序依次执行的,每个操作符都会接受一连串的文档,对这些文档做一些类型转换,最后将转换后的文档作为结果传递给下一个操作符(对于最后一个管道操作符,是将结果返回给客户端),称为流式工作方式。
- 管道操作符:$ match、$ group、$ sort、$ limit、$ skip、$unwind
- 管道操作符,只能用于计算当前聚合管道的文档,不能处理其它的文档。
8.1 $project-聚合投影约束
- $ project 操作符:我们可以使用$project 操作符做聚合投影操作。
- 查询 dev 集合,将数组中的内容拆分显示,并只显示 title 键与 tags 键的值
- db.dev.aggregate([{$ unwind:"$ tags"},{$ project:{_id:0,tags:"$ tags",title:"$title"}}])
- tags:"$tags":显示 tags 的值,字段名为 tags。
- title:"$title":显示 title 的值,字段名为 title。
- 查询 dev 集合,将数组中的内容拆分显示。要求只显示 title 键与 tags 键的值并将 title键修改为 Title。
- db.dev.aggregate([{$ unwind:"$ tags"},{$ project:{_id:0,tags:"$ tags",Title:"$title"}}])
- Title:"$title":显示 title 的值,字段名为 Title。
8.2 $project-字符串处理
- 在$project 中我们可以通过 MongoDB 的字符串操作符对投影的内容做字符串处理。
- 查询 dev 集合,将数组中的内容拆分显示。将 title 中的值换为小写并命名为 New_Title, 将 tags 的转换为大写并命名为 New_Tags。
- db.dev.aggregate([{$ unwind:"$ tags"},{ $ project:{_id:0,New_Title:{$ toLower:"$ title"},New_tags:{$ toUpper:"$tags"}}}])
- New_Title:{$ toLower:"$title"}:将 title 的值转换为小写,显示字段名为 New_Title。
- New_tags:{$ toUpper:"$tags"}:将 tags 的值转换为大写,显示字段名为 New_Tags。
- 查询 dev 集合,将数组中的内容拆分显示。将 title 字段和 tags 字段的值拼接为一个完整字符串并在 Title_Tags 字段中显示。
- db.dev.aggregate([{$ unwind:"$ tags"},{$ project:{_id:0,Title_Tags:{$ concat:["$ title","-","$tags"]}}}])
- Title_Tags:{$ concat:["$ title","-","$tags"]}:将字段 title 与字符串’-'和字段 tags 的值拼接为新的字符串,并显示字段名为 Title_Tags
- 查询 dev 集合,将数组中的内容拆分显示。只显示 title 字段的前 3 个字符,并命名为Title_Prefix
- db.dev.aggregate([{$ unwind:"$ tags"},{$ project:{_id:0,Title_Prefix:{$ substr:["$title",0,3]}}}])
- Title_Prefix:{$ substr:["$title",0,3]}:将 title 的值从0 开始截取截3 位,并命名为 Title_Prefix
- 我们可以看到对于汉字部分并未截取三位,原因是$ substr 只能匹配 ASCII 的数据,对于中文要使用$substrCP
8.3 $project-算术运算
- 在$project 中我们可以通过 MongoDB 的算数作符对投影的内容做运算处理。
- 查询 dev 集合中数据,显示 title 和 size 字段,为 size 字段数据做加 1 操作,显示字段命名为 New_Size。
- db.dev.aggregate([{$ project:{_id:0,title:1,New_Size:{$ add:["$size",1]}}}])
- New_Size:{$ add:["$size",1]}:在查询结果中,对size的值做加1处理,并命名为New_Size。
- 排除那些没有 size 键的文档。
- db.dev.aggregate([{$ match:{size:{$ ne:null}}},{$ project:{_id:0,title:1,New_Size:{$ add:["$size",1]}}}])
- $ match:{size:{$ne:null}:排除那些没有 size 的文档。
- 查询 dev 集合中数据,显示 title 和 size 字段,为 size 字段数据做减 1 操作,显示字段命名为 New_Size。
- db.dev.aggregate([{$ match:{size:{$ ne:null}}},{$ project:{_id:0,title:1,New_Size:{$ subtract:["$size",1]}}}])
- New_Size:{$ subtract:["$size",1]}:在查询结果中,对 size 的值做减 1 处理,并命名为New_Size。
- 查询 dev 集合中数据,显示 title 和 size 字段,为 size 字段数据做乘 2 操作,显示字段命名为 New_Size。
- db.dev.aggregate([{$ match:{size:{$ ne:null}}},{$ project:{_id:0,title:1,New_Size:{$ multiply:["$size",2]}}}])
- New_Size:{$ multiply:["$size",2]}:在查询结果中,对 size 的值做乘 2 处理,并命名为New_Size.
- 查询 dev 集合中数据,显示 title 和 size 字段,为 size 字段数据做除 2 操作,显示字段命名为 New_Size。
- db.dev.aggregate([{$ match:{size:{$ ne:null}}},{$ project:{_id:0,title:1,New_Size:{$ divide:["$size",2]}}}])
- New_Size:{$ divide:["$size",2]}:在查询结果中,对 size 的值做除 2 处理,并命名为New_Size
- 查询 dev 集合中数据,显示 title 和 size 字段,为 size 字段数据做模 2 操作,显示字段命名为 New_Size
- db.dev.aggregate([{$ match:{size:{$ ne:null}}},{$ project:{_id:0,title:1,New_Size:{$ mod:["$size",2]}}}])
- New_Size:{$ mod:["$size",2]}:在查询结果中,对size的值做模2处理,并命名为New_Size
8.4 $project-日期操作
8.4.1 MongoDB 中的日期处理
- 插入当前时间 db.dev.insert({date:new Date()})
- MongoDB 中的时间会比系统当前时间少 8 个小时。因为他的时间是 UTC 的时间,而中国的时区是东八区,比 UTC 快 8 个小时,所以会比当前时间少 8 个小时。
- 插入指定日期
- 方式一:
db.dev.insert({time:new Date(“2018-05-01T14:20:23Z”)})
new Date(“2018-05-01T14:20:23Z”):创建时间对象,日期格式为 yyyy-MM-ddThh:mm:ss
- 方式二:
db.dev.insert({time:ISODate(“2019-06-01T16:30:00Z”)})
ISODate(“2019-06-01T16:30:00Z”):
- 查询时间
- db.dev.find({time:{$eq:new Date(“2018-05-01T14:20:23”)}})
- 或者
- db.dev.find({time:{$gt:new Date(“2018-04-01”)}})
- 或者
8.4.2 $project-日期处理
- 向 dev 集合中插入一个文档,该文档包含 name:”admin” birth:”1990-05-01T13:30:00Z”
- 查询 dev 集合中数据,显示 birth 字段的各部分数据,包括:年、月、日等信息。
- 显示年月日
- db.dev.aggregate([{$ match:{name:“admin”}},{$ project:{ 年 份 :{$ year:"$ birth"}, 月 份:{$ month:"$ birth"}日:{$ dayOfMonth:"$birth"}}}])
- {$ year:"$birth"}年份
- {$ month:"$birth"}月份
- {$ dayOfMonth:"$birth"}日期
- 显示小时、分钟、秒、毫秒
- db.dev.aggregate([{$ match:{name:“admin”}},{$ project:{ 年 份 :{$ year:"$ birth"}, 月 份 {$ month:"$ birth"}, 日 :{$ dayOfMonth:"$ birth"}, 时 :{$ hour:"$ birth"}, 分 :{$ minute:"$ birth"},秒:{$ second:"$ birth"},毫秒:{$ millisecond:"$birth"}}}])
- {$ hour:"$birth"}:小时
- {$ minute:"$birth"}:分钟
- {$ second:"$birth"}:秒
- {$ millisecond:"$birth"}:毫秒
- 显示星期、全年的第几周、全年中的第几天
- db.dev.aggregate([{$ match:{name:“admin”}},{$ project:{ 年 份 :{$ year:"$ birth"}, 月 份 {$ month:"$ birth"}, 日 :{$ dayOfMonth:"$ birth"}, 时 :{$ hour:"$ birth"}, 分 :{$ minute:"$ birth"},秒:{$ second:"$ birth"},毫秒:{$ millisecond:"$ birth"},星期:{$ dayOfWeek:"$ birth"},全年的第几周:{$ week:"$ birth"},全年中的第几天:{$ dayOfYear:"$birth"}}}])
- {$ dayOfWeek:"$birth"}:星期日为 1,星期六为 7。
- {$ week:"$birth"}:全年的周计数从 0 开始。
- {$ dayOfYear:"$birth"}:全年中的第几天。
- 显示自定义日期格式
- db.dev.aggregate([{$ match:{name:“admin”}},{$ project:{ 年 份 :{$ year:"$ birth"}, 月 份 {$ month:"$ birth"}, 日 :{$ dayOfMonth:"$ birth"}, 时 :{$ hour:"$ birth"}, 分 :{$ minute:"$ birth"},秒:{$ second:"$ birth"},毫秒{$ millisecond:"$ birth"},星期:{$ dayOfWeek:"$ birth"},全年的第几周 :{$ week:"$ birth"}, 全 年 中 的 第 几 天:{$ dayOfYear:"$ birth"}, 自 定 义 日 期 格式:{$ dateToString:{format:"%Y 年%m 月%d 日%H:%M:%S",date:"$birth"}}}}])
- {$ dateToString:{format:"%Y 年%m月%d 日 %H:%M:%S",date:"$birth"}:自定义日期格式
- 具体格式如下: