mongodb聚合命令的参考与演示

2022-01-10

>Mongodb聚合命令数据准备聚合管道(aggregate)参考$addFields——向文档添加新字段$bucket——根据指定的表达式和存储区边界分组。$bucketAuto——* 根据指定的表达式和存储区数量分组$collStats——返回有关集合或视图的统计信息。$count——* 返回聚合管道此阶段的文档数量计数。$currentOp——查看当前数据库连接信息$facet——在同一组输入文档的单个阶段内处理多个聚合管道$geoNear——* 根据与地理空间点的接近程度返回一个有序的文档流$graphLookup——对集合执行递归搜索$group——* 对数据进行分组$indexStats——返回有关集合的每个索引的使用情况的统计信息$$limit——* 限制经过管道的文档数量$listSessions——列出足以传播到system.sessions集合的所有会话。$lookup——* 对同数据库中的另一个集合执行左外连接$match——过滤,筛选符合条件的文档,作为下一阶段输入$merge——将聚合管道的结果文档写入集合,它必须是管道中的最后一个阶段$out——* 将聚合管道的结果文档写入集合,它必须是管道中的最后一个阶段$planCacheStats——返回集合的计划缓存信息。$project——* 数据投影,主要用于重命名,增加,删除字段$redact——通过基于文档本身中存储的信息来重塑流中的每个文档。$replaceRoot——用指定的嵌入文档替换文档$replaceWith——* 用指定的嵌入文档替换文档$sample——* 从输入中随机选择指定数量的文档。$set——* 向文档添加新字段。$skip——* 待操作集合处理前跳过部分文档$sort——* 按指定的排序键重新排序文档$sortByCount——根据某字段分组,然后计算每个不同组中的文档计数$unionWith——* 执行两个集合的并集$unset——* 从文档中移除/排除字段$unwind——解析输入文档中的数组字段,为每个元素输出一个文档Map-Reduce使用aggregate来替换MapReduce单用聚合操作estimatedDocumentCountcountdistinct其他

Mongodb聚合命令

聚合管道( aggregate )

Map-Reduce

单用聚合操作( estimatedDocumentCount、count、distinct )

数据准备

查看其中一条数据

image-20220110102744052

聚合管道(aggregate)

参考

参考资料:聚合管道快速参考 - MongoDB-CN-Manual (mongoing.com)

MongoDB聚合 - MongoDB-CN-Manual (mongoing.com)

注意:除 $out, $merge$geoNear阶段之外的所有阶段都可以在管道中多次出现

聚合管道只作查询用途,任何操作都是基于查询结果,并不会影响源文档信息

$addFields——向文档添加新字段

如向文档中添加老师信息:

image-20220105163629038

$bucket——根据指定的表达式和存储区边界分组。

如按照成绩分组分为,0-60:不及格、60-80:及格、80-90:良好、90-100:优秀

注意这是一个左闭右开的区间范围,如 90-100 是不包含 100 分的,而我们提供的区间又没有 100分 这个区间,所以会默认分到"其他"区间

image-20220105170710890

$bucketAuto——* 根据指定的表达式和存储区数量分组

如按照成绩分成3组:

image-20220105173926425

$collStats——返回有关集合或视图的统计信息。

语法:

latencyStats——查看延迟信息

latencyStats.histograms——如果true,则将延迟直方图信息也显示出来

storageStats——查看集合的基本存储信息、如集合大小、条数、平均每条大小等等等等

count————————查看集合的总条数

简单演示,默认仅显示集合名称、主机、UTC时间

image-20220105175153181

查看延迟信息

image-20220105175401127

查看延迟信息、直方图信息(我也不知道直方图是什么,只知道信息更多了)

image-20220105175527962

查看集合存储的信息

image-20220105175722570

查看集合总条数

image-20220105175804903

当然这几个都可以组合一起使用的

$count——* 返回聚合管道此阶段的文档数量计数。

语法:

简单示例

image-20220105180357766

$currentOp——查看当前数据库连接信息

语法:

简单示例

image-20220107150241016

image-20220107150708812

$facet——在同一组输入文档的单个阶段内处理多个聚合管道

v3.4+ 可用

语法:

简单示例,如将 age 分成两组,以30为分界线

image-20220107172402532

$geoNear——* 根据与地理空间点的接近程度返回一个有序的文档流

语法:

准备数据

简单示例,查询与 [ -73.002, 40.005 ] 距离 1000 米内的点(单位应该是米吧)

$graphLookup——对集合执行递归搜索

语法:

准备数据

官方示例,找领导。

如 Dan,他要向 Andrew 汇报,Andrew 再向 Eliot 汇报,Eliot 再向 Dev汇报,所以 Dan字段就会出现3个领导信息,

再如 Dev,他是最高领导,它不需要向其他人汇报,所以 Dev 不会出现任何领导信息

image-20220107184826912

演示

image-20220110144437038

$group——* 对数据进行分组

image-20220105181925449

$indexStats——返回有关集合的每个索引的使用情况的统计信息$

image-20220105182415095

$limit——* 限制经过管道的文档数量

image-20220105182808665

$listSessions——列出足以传播到system.sessions集合的所有会话。

仅对config库有用

image-20220105184214074

image-20220105184358775

$lookup——* 对同数据库中的另一个集合执行左外连接

语法:

如我们要同时查出学生信息及学生住址

image-20220106101457840

使用 let 做匹配,往往用在两个以上条件匹配时才会用到的

image-20220106165212635

需要注意的点:

  1. pipeline 作用域内可以直接读取外表的字段。也可以读取主表的字段,但可能会出现变量作用域混乱的情况,如下图,我们可以看到取到的地址信息都是同一个,这肯定是不正确的

image-20220106103538866

  1. pipeline 内的 $project 只能限制外表的字段,也就是说只能控制外表哪些字段可以显示哪些不可现实。 {$project:{'_id':0}} 意思是不展示地址表中的 _id 字段,如果要限制主表应该将 $project 与 $lookup 平级,如下:

image-20220106104527718

{$project:{'score':0,'age':0,'student_info.detail':0}} 即 不展示学生主表中的 score、age 字段,不展示 student_info.detail 字段

$match——过滤,筛选符合条件的文档,作为下一阶段输入

image-20220106105302256

$merge——将聚合管道的结果文档写入集合,它必须是管道中的最后一个阶段

v4.2+——可以指定输出到某个库某个集合

v4.4+——可以输出到原集合

语法:

简单示例

image-20220106113850039

再来看一下指定字段的。指定 _id 字段 其实和不指定on一样的效果

image-20220106114845798

指定多字段。

1.要先对这些字段建索引,无关顺序

2.一定要加上 {$project:{_id:0}} _id 排除将否则会报错:

PlanExecutor error during aggregation :: caused by :: $merge failed to update the matching document, did you attempt to modify the id or the shard key? :: caused by :: Performing an update on the path 'id' would modify the immutable field '_id'

原先我们 new_coll 集合中只有 1、2、3三条记录,students集合中有 1、2、3、4、5、6 六条记录,根据两张表的age、name字段作比较,刚好 students 的 1、2、3 记录能匹配上 new_coll 的 1、2、3 记录,那么程序会将不存在于 new_coll 集合的字段合并到 new_coll 相应记录中。而 4,5,6 记录未能匹配,则程序会将这些记录插入到 new_coll 中,由于这些是没有 _id 的,所以 mongodb 会自动创建一个 _id 字段。

image-20220106150020905

$out——* 将聚合管道的结果文档写入集合,它必须是管道中的最后一个阶段

v4.4+——可以输出到指定数据库的某个集合

语法:

简单例子

image-20220106154025806

$planCacheStats——返回集合的计划缓存信息。

v4.2+ 可用

image-20220106155435178

$project——* 数据投影,主要用于重命名,增加,删除字段

语法:

简单示例,如果不对 _id 进行设置的话,默认出现,如不希望 _id 出现,应该将值设为0

image-20220106163802907

添加字段 time 、重命名字段 sex_sex

image-20220106170634162

还可以指定 pipeline 做判断。如下我们可以通过计算方法来得出 age、score 这两个字段的平均值,也可以通过判断如果年龄小于 30 ,则不显示 sex 字段

image-20220106175330028

$redact——通过基于文档本身中存储的信息来重塑流中的每个文档。

合并$project$match的功能, $redact 常与 $cond 一起使用,相关变量功能:$$DESCEND 不包括嵌套对象、$$PRUNE——排除该字段、$$KEEP——保留该字段

语法:

数据准备 new_coll

image-20220106181112883

简单示例,含有教师信息的学生记录

我们可以看到 $$PRUNE 直接将 sex != '男' 记录排除了,而第一条命令用 $$DESCEND 并没有把 teacher 展示出来,第二条命令在一样的条件下使用 $$KEEP 是可以把 teacher 字段展示出来的

image-20220106182340836

$replaceRoot——用指定的嵌入文档替换文档

v3.4+ 可用

语法:

简单示例,有点像 $project 的感觉

image-20220107095239396

更复杂的,如输出学生信息和成绩

image-20220107100020304

与 $mergeObjects 配合使用,查询 new_coll 集合中的教师信息,若没有则默认补上"无"

image-20220107101048931

$replaceWith——* 用指定的嵌入文档替换文档

v4.2+ 可用, $replaceRoot 能用的 $replaceWith 基本也可以用,只是语法少了 newRoot 属性

语法:

简单使用

image-20220107102314258

更复杂的,如输出学生信息和成绩

image-20220107102427199

与 $mergeObjects 配合使用,查询 new_coll 集合中的教师信息,若没有则默认补上"无"

image-20220107102737186

$sample——* 从输入中随机选择指定数量的文档。

v3.2+ 可用

语法:

简单示例,随便取出3条记录

image-20220107103110513

$set——* 向文档添加新字段。

v4.2+可用,与$project 类似,$set会重新塑造流中的每个文档。$set$addFields阶段的别名。

语法:

简单示例,查询时加一个 age、score 字段的平均值

image-20220107104030141

处理数组

image-20220107104652594

$skip——* 待操作集合处理前跳过部分文档

简单示例

image-20220107104938717

$sort——* 按指定的排序键重新排序文档

image-20220107105142640

$sortByCount——根据某字段分组,然后计算每个不同组中的文档计数

v3.4+ 可用

简单示例,按照学生成绩分组,并根据数量倒排

image-20220107105647102

$unionWith——* 执行两个集合的并集

v4.4+ 可用

简单示例

image-20220107141627946

$unset——* 从文档中移除/排除字段

v4.2 可用

简单示例

image-20220107142157577

$unwind——解析输入文档中的数组字段,为每个元素输出一个文档

v3.2+ 可用

语法:

简单示例

image-20220107143233127

查看下标

image-20220107144021785

Map-Reduce

流程:先筛选一层(query),通过cust_id进行分组(map),获取分组后每一组的数量(reduce),再进行输出(output)

41

简单示例

image-20220110110200634

emit一定是要两个参数,如果你想输出整个对象直接指定this即可,如果你只想输出一个属性,如name,应该这样写:emit(this.sex, this.name),如果你像输出特定(两个以上)的属性,如name、age,我们可以这样写:emit(this.sex,{name:this.name,age:this.age}),千万不要这样写:emit(this.sex,{name,age})

这个out是覆盖写入的

image-20220110112400968

使用aggregate来替换MapReduce

image-20220110121839221

单用聚合操作

estimatedDocumentCount

v4.0.3+ 可用,计算集合总数

image-20220110113216581

对于搜索无效

image-20220110113411498

count

计算集合总数,可搜索、可过滤、可提取、可设置读关注、可设置超时时间

语法:

简单示例

image-20220110114705766

distinct

按照字段筛选重复项

语法:

image-20220110115456133

其他

本来是不打算记录的,因为文档上该有的都有,例子也很鲜明通俗易懂,但看着看着总觉得还得自个抄一下,才能更深刻一点。aggregate 是个很实用得东西,对复杂查询、查询速度这两个操作比直接find效率要高很多,我们要学的不是语法,而是要学会将各个阶段得命令结合起来,更快查询到我们想要的东西。

含 * 的可能是平常比较常见、用得比较多命令吧。(该叫它命令呢?还是阶段?)

下一篇找时间整理一下mongodb得常见函数。