首页 > 数据库 >MongoDB基础之分组聚合函数讲解

MongoDB基础之分组聚合函数讲解

时间:2022-11-05 19:12:54浏览次数:35  
标签:like 1.2 author MongoDB db book 分组 讲解 id

目录

1 分组聚合

1.1 概念定义

MongoDB 中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。
有点类似 SQL 语句中的 count(*)

管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。

表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。

1.2 聚合操作

准备脚本

> db.book.insertMany([
{"_id": 1, "author": "monday", "book": "《Java》", "like": 10}, 
{"_id": 2, "author": "monday", "book": "《Java Core》", "like": 20}, 
{"_id": 3, "author": "mengday", "book": "《Spring Boot》", "like": 15}
])

> db.book.find()
{ "_id" : 1, "author" : "monday", "book" : "《Java》", "like" : 10 }
{ "_id" : 2, "author" : "monday", "book" : "《Java Core》", "like" : 20 }
{ "_id" : 3, "author" : "mengday", "book" : "《Spring Boot》", "like" : 15 }

1.2.1 $match筛选

用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
筛选条件,相当于SQL中的where部分,过滤掉不满足条件的文档,可以使用常规的查询操作符,如 $gt$lt$in等。

> db.book.aggregate({"$match": {"like": {"$gt": 10}}})
{ "_id" : 2, "author" : "monday", "book" : "《Java Core》", "like" : 20 }
{ "_id" : 3, "author" : "mengday", "book" : "《Spring Boot》", "like" : 15 }

1.2.2 $project映射

$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
映射相当于SQL中的 select 映射 from 之间的部分,用于指定要查询的字段,或者对字段进行一些处理。
投射常用的3个功能:

  • 对字段重命名。
  • 在投射中使用一些表达式对字段值进行处理:数学表达式、日期表达式、字符串表达式、逻辑表达式(比较表达式、布尔表达式、控制语句)。
  • 用于包含、排除字段: 设置要查询或者要过滤掉的字段,
    • 0: 要过滤掉的字段,不显示
    • 1:需要查询的字段。

1.2.2.1 自定义字段

查询自定义的字段

db.book.aggregate({"$project": {"_id": 0, "book": 1, "like": 1}})
{ "book" : "《Java》", "like" : 10 }
{ "book" : "《Java Core》", "like" : 20 }
{ "book" : "《Spring Boot》", "like" : 15 }

1.2.2.2 起别名

对字段起别名,相当于SQL中的as的作用

db.book.aggregate({"$project": {"_id": 0, "book name": "$book", "like": 1}})
{ "like" : 10, "book name" : "《Java》" }
{ "like" : 20, "book name" : "《Java Core》" }
{ "like" : 15, "book name" : "《Spring Boot》" }

1.2.2.3 引用原字段:$字段名

如果对_id进行起别名会将别名作为一个新的字段加入到文档中,而_id保持不变

db.book.aggregate({"$project": {"id": "$_id", "book name": "$book", "like": 1}})
{ "_id" : 1, "like" : 10, "id" : 1, "book name" : "《Java》" }
{ "_id" : 2, "like" : 20, "id" : 2, "book name" : "《Java Core》" }
{ "_id" : 3, "like" : 15, "id" : 3, "book name" : "《Spring Boot》" }

1.2.2.4 使用算术表达式

使用算术表达式 $add$subtract$multiply$divide$mod 处理数字类型的字段

db.book.aggregate({"$project": {"like": {"$add": ["$like", "$like", 1]}}})
{ "_id" : 1, "like" : 21 }
{ "_id" : 2, "like" : 41 }
{ "_id" : 3, "like" : 31 }

1.2.2.5 字符串截取

$substrCP: [exp, startOffset, numToReturn] : 字符串截取操作

db.book.aggregate({"$project": {"newValue": {"$substrCP": ["$book", 1, 4]}}})
{ "_id" : 1, "newValue" : "Java" }
{ "_id" : 2, "newValue" : "Java" }
{ "_id" : 3, "newValue" : "Spri" }

1.2.2.6 字符串拼接

$concat:[exp1, exp2, ..., expN]: 字符串操作:将数组中的多个元素拼接在一起

db.book.aggregate({"$project": {"newValue": {"$concat": ["$book", "(", "$author", ")"]}}})
{ "_id" : 1, "newValue" : "《Java》(monday)" }
{ "_id" : 2, "newValue" : "《Java Core》(monday)" }
{ "_id" : 3, "newValue" : "《Spring Boot》(mengday)" }

1.2.2.7 大小写转换

$toUpper: 字符串操作,转大写
$toLower: exp, 字符串转小写

db.book.aggregate({"$project": {"newValue": {"$toUpper": "$book"}}})
{ "_id" : 1, "newValue" : "《JAVA》" }
{ "_id" : 2, "newValue" : "《JAVA CORE》" }
{ "_id" : 3, "newValue" : "《SPRING BOOT》" }

1.2.2.8 日期表达式

日期表达式:用于获取日期中的任意一部分,年月日时分秒 星期等
$year$month$dayOfMonth$dayOfWeek$dayOfYear$hour$minute$second

  • $dayOfYear: 返回该日期是这一年的第几天(全年 366 天)。
  • $dayOfMonth: 返回该日期是这一个月的第几天(1到31)。
  • $dayOfWeek: 返回的是这个周的星期几(1:星期日,7:星期六)。
  • $year: 返回该日期的年份部分。
  • $month: 返回该日期的月份部分( 1 到 12)。
  • $week: 返回该日期是所在年的第几个星期( 0 到 53)。
  • $hour: 返回该日期的小时部分。
  • $minute: 返回该日期的分钟部分。
  • $second: 返回该日期的秒部分(以0到59之间的数字形式返回日期的第二部分,但可以是60来计算闰秒)。
  • $millisecond:返回该日期的毫秒部分( 0 到 999)。
  • $dateToString: { $dateToString: { format: , date: } }。

准备脚本

db.book.find()
{ "_id" : 1, "author" : "monday", "book" : "《Java》", "like" : 10, "publishDate" : ISODate("2021-04-12T13:38:14.829Z") }
{ "_id" : 2, "author" : "monday", "book" : "《Java Core》", "like" : 20, "publishDate" : ISODate("2021-04-12T13:38:14.829Z") }
{ "_id" : 3, "author" : "mengday", "book" : "《Spring Boot》", "like" : 15, "publishDate" : ISODate("2021-04-12T13:38:14.829Z") }

求日期

db.book.aggregate({"$project": {"year": {"$year": "$publishDate"}}})
{ "_id" : 1, "year" : 2021 }
{ "_id" : 2, "year" : 2021 }
{ "_id" : 3, "year" : 2021 }

1.2.2.9 比较非字符串大小

$cmp: [exp1, exp2]: 用于比较两个非字符串类型的值,exp1 == exp2 返回 0, 小于返回一个负数,大于返回一个正数

db.book.aggregate({"$project": {"result": {"$cmp": ["$like", 15]}}})
{ "_id" : 1, "result" : -1 }
{ "_id" : 2, "result" : 1 }
{ "_id" : 3, "result" : 0 }

1.2.2.10 比较字符串大小

$strcasecmp: 用于比较字符串, 不区分大小写,相等返回0

db.book.aggregate({"$project": {"result": {"$strcasecmp": ["$author", "Monday"]}}})
{ "_id" : 1, "result" : 0 }
{ "_id" : 2, "result" : 0 }
{ "_id" : 3, "result" : -1 }

1.2.2.11 比较表达式

$eq: 用于判断两个表达式是否相等,相等返回true,不相等返回false, 区分大小写
$ne: 不相等
$gt: 大于
$gte: 大于等于
$lt: 小于
$lte: 小于等于
注意:{"$eq": ["$author", "monday"]}$eq键的值是个数组而不是一个对象

db.book.aggregate({"$project": {"result": {"$eq": ["$author", "monday"]}}})
{ "_id" : 1, "result" : true }
{ "_id" : 2, "result" : true }
{ "_id" : 3, "result" : false }

1.2.2.12 And连接

$and:[exp1, exp2, ..., expN] 用于连接多个条件,当所有条件为真的时候为true

db.book.aggregate({"$project": {"result": {"$and": [{"$eq": ["$author", "monday"]}, {"$gt": ["$_id", 1]}]}}})
{ "_id" : 1, "result" : false }
{ "_id" : 2, "result" : true }
{ "_id" : 3, "result" : false }

1.2.2.13 Or连接

$or: [exp1, exp2, ..., expN]有一个为真则为真

db.book.aggregate({"$project": {"result": {"$or": [{"$eq": ["$author", "monday"]}, {"$eq": ["$_id", 1]}]}}})
{ "_id" : 1, "result" : true }
{ "_id" : 2, "result" : true }
{ "_id" : 3, "result" : false }

1.2.2.14 not连接

$not: exp 用于取反操作

db.book.aggregate({"$project": {"result": {"$not": {"$eq": ["$author", "monday"]}}}})
{ "_id" : 1, "result" : false }
{ "_id" : 2, "result" : false }
{ "_id" : 3, "result" : true }

1.2.2.15 三位运算符

$cond: [booleanExp, trueExp, falseExp]: 三位运算符

db.book.aggregate({"$project": {"result": {"$cond": [ {"$eq": ["$author", "monday"]}, "M", "F" ]}}})
{ "_id" : 1, "result" : "M" }
{ "_id" : 2, "result" : "M" }
{ "_id" : 3, "result" : "F" }

1.2.2.16 ifNull连接

$ifNull: [expr, replacementExpr]: 如果字段不存在或者字段值为null会返回replacementExpr,否则返回原来的值,即字段为空时给一个默认值
IFNULL(bool, default_value)

db.book.aggregate({"$project": {"result": {"$ifNull": ["$price", "0.00"]}}})
{ "_id" : 1, "result" : 66 }
{ "_id" : 2, "result" : "0.00" }
{ "_id" : 3, "result" : "0.00" }

1.2.3 $group 分组

1.2.3.1 单字段分组

相当于SQL中的group by 部分
$group 表示分组
_id: 用于指定要分组的字段
count: 是聚合后的结果的字段别名,类似于SQL中的as后面的别名,可以任意定义,字段前面使用$表示应用某个字段而不是一个普通的字符串
$sum: 对分组中的每个文档做什么类型的聚合,是求和还是求平均数等,1:表示对分组的每一条文档都加1进行统计,这就相当于SQL中的count(*)
select _id, count(*) from book group by author

db.book.aggregate({"$group": {"_id": "$author", "count": {"$sum": 1}}})
{ "_id" : "monday", "count" : 2 }
{ "_id" : "mengday", "count" : 1 }

1.2.3.2 对多个字段进行分组

类似于:select _id, count(*) from book group by author, like

db.book.aggregate({"$group": {"_id": {"author": "$author", "like": "$like"}, "count": {"$sum": 1}}})
{ "_id" : { "author" : "monday", "like" : 10 }, "count" : 1 }
{ "_id" : { "author" : "monday", "like" : 20 }, "count" : 1 }
{ "_id" : { "author" : "mengday", "like" : 15 }, "count" : 1 }

1.2.3.3 聚合运算

$avg: 求分组中某个字段的平均值
$max: 求分组中某个字段的最大值
$min: 求分组中某个字段最小的值
$first: 求分组中的第一个值
$last: 求分组中最后一个值

db.book.aggregate( {"$group": {"_id": "$author", "avg": {"$avg": "$like"}}} )
{ "_id" : "monday", "avg" : 15 }
{ "_id" : "mengday", "avg" : 15 }

1.2.3.4 addToSet

$addToSet: 字段引用, 将分组后的每个文档指定的值放在set集合中,集合不重复,无序

db.book.aggregate( {"$group": {"_id": "$author", "likes": {"$addToSet": "$like"}}} )
{ "_id" : "monday", "likes" : [ 20, 10 ] }
{ "_id" : "mengday", "likes" : [ 15 ] }

1.2.3.5 push操作

$push: exp, 将分组后的每个文档指定的值放在数组中,允许重复,有序

db.book.aggregate( {"$group": {"_id": "$author", "likes": {"$push": "$like"}}} )
{ "_id" : "mengday", "likes" : [ 15 ] }
{ "_id" : "monday", "likes" : [ 10, 20 ] }

1.2.4 $unwind

将数组的每一个元素都单独作为一条文档进行拆分。

 db.comments.insert({"_id": 1, "title": "java", "comment": ["good", "very good"]})
db.comments.find()
{ "_id" : 1, "title" : "java", "comment" : [ "good", "very good" ] }

db.comments.aggregate( {"$unwind": "$comment"} )
{ "_id" : 1, "title" : "java", "comment" : "good" }
{ "_id" : 1, "title" : "java", "comment" : "very good" }

1.2.5 $sort

对文档进行排序,相当于SQL中的order by。

db.book.aggregate( {"$sort": {"_id": -1}} )
{ "_id" : 3, "author" : "mengday", "book" : "《Spring Boot》", "like" : 15, "publishDate" : ISODate("2021-04-12T13:38:14.829Z") }
{ "_id" : 2, "author" : "monday", "book" : "《Java Core》", "like" : 20, "publishDate" : ISODate("2021-04-12T13:38:14.829Z"), "price" : null }
{ "_id" : 1, "author" : "monday", "book" : "《Java》", "like" : 10, "publishDate" : ISODate("2021-04-12T13:38:14.829Z"), "price" : 66 }

1.2.6 $limit

限制返回的条数,相当于SQL中的limit count 语句。

db.book.aggregate( {"$limit": 2} )
{ "_id" : 1, "author" : "monday", "book" : "《Java》", "like" : 10, "publishDate" : ISODate("2021-04-12T13:38:14.829Z"), "price" : 66 }
{ "_id" : 2, "author" : "monday", "book" : "《Java Core》", "like" : 20, "publishDate" : ISODate("2021-04-12T13:38:14.829Z"), "price" : null }

1.2.7 $skip

跳过前N条文档,和limit结合可用于分页。

db.book.aggregate( {"$skip": 2}, {"$limit": 2} )
{ "_id" : 3, "author" : "mengday", "book" : "《Spring Boot》", "like" : 15, "publishDate" : ISODate("2021-04-12T13:38:14.829Z") }

1.2.8 综合使用

聚合框架,就是将上一个操作符处理的结果交个下一个操作符继续处理(这就是Linux中的管道操作),可以使用任意多个操作符,同一个操作符也可以使用多次

  • 首先通过$match过滤掉不匹配的文档,
  • 接着讲满足条件的文档交给$group进行分组,
  • 分组后将将分组后的结果交给$sort进行排序,
  • 然后将排序后的结果交给$skip处理,跳过前几条,
  • 把剩下的文档交给$limit处理,获取最终的聚合结果。
db.book.aggregate( 
    {"$match": {"like": {"$gte" : 10} }}, 
    {"$group": {"_id": "$author", "count": {"$sum": 1}}},
    {"$sort": {"count": -1}},
    {"$skip": 1},
    {"$limit": 1} 
)

{ "_id" : "mengday", "count" : 1 }

1.3 常见聚合表达式

下表展示了一些聚合的计算表达式:

表达式 描述 实例
$sum 计算总和 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}])
$avg 计算平均值 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])
$min 获取集合中所有文档对应值得最小值 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}])
$max 获取集合中所有文档对应值得最大值。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}])
$push 将值加入一个数组中,不会判断是否有重复的值 db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}])
$addToSet 将值加入一个数组中,会判断是否有重复的值,若相同的值在数组中已经存在了,则不加入。 db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])
$first 根据资源文档的排序获取第一个文档数据。 db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}])
$last 根据资源文档的排序获取最后一个文档数据 db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}])

标签:like,1.2,author,MongoDB,db,book,分组,讲解,id
From: https://www.cnblogs.com/jingzh/p/16860861.html

相关文章

  • MongoDB基础之索引分析
    目录1索引1.1定义1.2创建索引1.3查看删除索引1.4查询分析1.4.1索引分析explain1.4.2强制使用索引hint1.5嵌套索引1.5.1索引数组字段1.5.2索引子文档字段1.6全......
  • CH58X/CH57X/V208的Broadcaster(广播者)例程讲解
    在对ble进行应用的时候,每个用户的需求可能不尽相同。这里着重介绍从机Broadcaster例程,只广播不连接。使用该例程时可以在手机使用APP上对Broadcaster进行调试。安卓端在......
  • mongodb 导出操作
    我的是备份数据库,链接到数据库服务器来备份的终端shell命令实现远程连接服务器:mongo-host10.202.***.**-port27017--authenticationDatabasexz**导出远程服......
  • Spring Data MongoDB--MongoTemplate查询数据--方法/实例
    简介说明        本文用示例介绍SpringDataMongoDB(MongoTemplate)查询数据的方法。查询方法分类mongoTemplate.find //返回listmongoTemplate.findOne //返回1......
  • 【云原生】Redis on k8s 编排部署讲解与实战操作
    目录一、概述二、redis主从模式编排部署实战操作1)下载chart包2)构建镜像3)修改yaml编排4)开始部署5)测试验证6)卸载三、redis哨兵模式编排部署实战操作1)构建镜像2)修改yaml编......
  • Ansible - 2 - 命令讲解
    Ansible命令命令集#以下所有命令均可使用`-h`参数获取帮助信息ansible#Defineandrunasingletask'playbook'againstasetofhosts#常用命......
  • .Net Core 3.0 对 MongoDB 的多条件(两种)查询操作
    前言  在日常开发中,偶尔会用到MongoDB的数据操作,也花费了一些时间调试,因此在此处记录一下,共同进步。废话少说,出招吧!正文2.1准备工作首先需要引入.Net平台链接......
  • Springboot 整合mongodb 操作工具类仿mybatis-plus风格
    https://blog.csdn.net/weixin_40986713/article/details/124192456优化点 有时间可以慢慢全部优化成mybatis-plus风格privateQueryeqQuery(Map<String,Object>dat......
  • MySQL函数-Group_Concat分组并行转列
    group_concat函数解析:1、concat()函数:  功能:将多个字符串连接成一个字符串  语法:concat(str1,str2)  结果:连接参数str1,str2为一个字符串,如果有任何一个参数为n......
  • 使用JdbcTemplate操作数据库(增删改查)。具体代码+讲解 【上篇】
    1、什么是JdbcTemplateSpring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作2、前提准备2.1在项目中引入对应的jar包官网下载jar包、然后加入的项目......