初识Mongodb之聚合管道篇

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
简介: 初识Mongodb之聚合管道篇


目录

 

高级操作

聚合管道 aggregate(操作列表[{},{},{}])

count()数量

distinct()

$avg平均值聚合

批处理框架

批处理结构重复代码

解开数组

总结


高级操作

聚合管道 aggregate(操作列表[{},{},{}])

在mysql里面,我们可以输出平均值,最大值,最小值,总数,方差等数理统计的一些参数,如果你问在MongoDB里面可不可以,我只能说你想要的没有不可以,哈哈哈。技术的改革和迭代总是在维护我们这些使用者的权益,只要想要的功能,开发者会尽所能的开发出发相应的功能,下面我们就来看看吧!


这些集合运算是在聚合管道里面的:

$avg: 求平均值
$sum: 求和
$max: 求最大值
$min: 求最小值

$group:聚合字段

 

count()数量

var 查询条件={'grade':2019,'class':1,'major':'大数据'};
db.students.find(查询条件).count()

distinct()

db.students.distinct('courses.course')

image.png

$avg平均值聚合


$group:{_id:groupby字段名,'聚合字段名':{$集合操作符:$字段名}}  : 注意在字段里面必须要加入$符号,这样才能取到该字段对应的值

_id:groupby字段名:相当于mysql里面要按照什么字段聚合,而对于后面的集合操作运算符就类似于MySQL里面的一些数据提取和运算

按照专业进行分组最后来求出每一个专业的平均分!

// 按专业取所有学生的平均身高
db.getCollection("students").aggregate([
{$group:{_id:"$major", avgHeight:{$avg:"$height"}}}
])

image.png

小例子

// 按专业求女生平均身高低于170的专业平均身高,并排序
/*
SQL: select AVG(height) as avgHeight, major as _id
  from students
where gender=0
group by major
having avgHeight>170
sorted by avgHeight DESC
*/
db.getCollection("students").aggregate([
//第一步,查数据
{$match:{gender:0}}
//第二步,限制返回字段
,{$project:{_id:0,major:1, grade:1, class:1, height:1}}
//第三步,分组求平均值
// _id: group by的字段, 字段名要加$符号前缀,表示是一个字段名
// avgHeight: 新生成的平均值字段名
// $avg: 平均值操作符,它的值为要求平均值的字段名,注意加$前缀
,{$group:{_id:"$major", avgHeight:{$avg:"$height"}}
//第四步,筛选聚合结果
,{$match:{avgHeight:{$lte:170}}}
//第五步,排序,按照avgHeight的值从大到小排序, -1: DESC, 1:ASC
,{$sort:{avgHeight:-1}}
])

批处理框架

对于MongoDB里面的查询和高级聚合操作,我们发现细节的东西有的多,我们应该如何去书写我们的查询代码呢,我的建议首先就是要有一个大的思维,我们已经学习了很多的小模块的,我们的目的是如何把这些和我们的日常开发结合在一起,在遇到实际的业务问题我们就可以很好地解决这些。

use cqust;
db.students.renameCollection('stu')

使用该方法可以进行查询,我们之前的find命令也可以实现这个,但是在函数里面进行批量的操作我们还是需要这种方法的。

// 聚合
// 1. count() distinct()
db.stu.count()
db.stu.count({'gender':1})  // 男生数量
db.stu.distinct("major") // 专业名称唯一列表
db.stu.distinct("courses.course") // 课程名称唯一列表

image.png

// cursor自带的统计函数
db.stu.find().count()
db.stu.find().sort()  // sort by _id
db.stu.find().sort({'body.height':1})  //1:升序 小->大
db.stu.find().sort({'body.weight':-1})  //-1:降序 

至于我们应该如何记住这个属性代表的是什么:1最原始的想法就是:从小到大(升序)

批处理结构重复代码

最初的方法

// 2. aggregate pipline聚合管道
// db.stu.find({},{})
var 查询条件 = {gender:0}
var 返回条件 = {_id:0, name:1, sno:1, gender:1}
db.stu.find(查询条件,返回条件)

结构思维

如何在使用我们的代码以及方法的时候可以快速的达到我们的要求

// 步骤 = {$步骤操作符:{步骤操作文档}}
// 查询女生条目
var 步骤1 = {$match:{gender:0}}
var 批处理 = [步骤1]
db.stu.aggregate(批处理)

image.png

// 步骤 = {$步骤操作符:{步骤操作文档}}
// 查询女生的姓名、性别、学号、身高字段
var 查询条件 = {gender:0}
var 返回条件 = {_id:0, 'name':1, 'sno':1, 'gender':1, 'body.height':1}
var 步骤1 = {$match:查询条件}   // $match 查询匹配
var 步骤2 = {$project:返回条件} // $project 返回条件
var 批处理 = [步骤2,步骤1]
//var 批处理 = [步骤1,步骤2]
db.stu.aggregate(批处理)
// 查询女生的平均身高字段
// select '女生平均身高', AVG(a.height) from (select height from stu where gender=0) a
var 查询条件 = {gender:0}
var 返回条件 = {_id:0, '身高':'$body.height'}
var 步骤1 = {$match:查询条件}   // 查询出所有的女生
var 步骤2 = {$project:返回条件} // 的身高
//var 批处理 = [步骤1,步骤2]
//db.stu.aggregate(批处理)
// $group:{_id:by字段, 聚合结果字段:{$聚合操作:}, }
var 步骤3 = {$group:{_id:'女生平均身高',平均身高:{$avg:'$身高'}}}    
var 批处理 = [步骤1,步骤2,步骤3]
db.stu.aggregate(批处理)
// 查询女生的平均身高字段
// select gender,AVG(height) '平均身高' from stu  group by gender having gender=0
var 步骤1 = {$group:{_id:'$gender',平均身高:{$avg:'$body.height'}}} //先分组计算平均身高
var 查询条件 = {_id:0}
// var 返回条件 = {_id:1, '平均身高':1}
var 步骤2 = {$match:查询条件}   // 从分组计算结果中筛选出女生(_id:0)的记录
// var 步骤3 = {$project:返回条件} // 的身高
var 管道 = [步骤1,步骤2]
db.stu.aggregate(管道)

同样的道理,这里首先按照性别将身高进行分组,然后利用集合操作就可以计算出我们想要的数据结果了,然后我们查询条件里面的$match:查询条件 就可以只查询我们想要查询的数据

// 统计各专业学生的平均身高
var s1 = {$group:{_id:'$major', 平均身高:{$avg:'$body.height'}}} //先分组计算平均身高
var ps = [s1]
db.stu.aggregate(ps)
// 统计各专业班级的学生平均身高
var s1 = {$group:{_id:{专业:'$major',班级:'$class'}, 平均身高:{$avg:'$body.height'}}} //先分组计算平均身高
var ps = [s1]
db.stu.aggregate(ps)

注意:当我们需要利用多个聚合字段进行操作的时候,我们依然和MySQL一样,按照逗号分割,这样就可以达到多个字段的分组,同时我们应该注意用$字段名取出我们的字段数据值

// 统计各专业班级的学生平均身高,并按专业排序
var s1 = {$group:{_id:{专业:'$major',班级:'$class'}, 平均身高:{$avg:'$body.height'}}} //先分组计算平均身高
var s2 = {$sort:{'_id.专业':1, '_id.班级':-1}}
var ps = [s1,s2]
db.stu.aggregate(ps)

这里增加了一个排序功能,利用$sort:{字段名:-1}

image.png

// 统计各专业男女生平均身高,按身高排序
var s1 = {$group:{_id:{专业:'$major',性别:'$gender'}, 平均身高:{$avg:'$body.height'}}} //先分组计算平均身高
var s2 = {$sort:{'平均身高':-1}}
var ps = [s1,s2]
db.stu.aggregate(ps)

这里把两个批处理的步骤放在了一个列表里面,这就是我们框架,首先有一个大的列表,然后这个大的列表里面可以存放很多小的处理,这样就是批处理的核心思想了

// 统计各专业学生的身高最大和最小值, 按专业排序
// _id.专业   最大身高$max    最小身高$min
var 分组聚合步骤 = {$group:{'_id':'$major', 最大身高:{$max:'$body.height'} , 最小身高:{$min:'$body.height'} }}
var 排序步骤 = {$sort:{_id:1}}
var 批处理 = [分组聚合步骤,排序步骤]
db.stu.aggregate(批处理)

框架如下:

var step = {$match:{}}    // 查询匹配
var step = {$group:{}}    // 分组 {$max:$field} {$min:$field} {$avg:$field} {{$sum:$field}}
var step = {$project:{}}  // 返回条件
var step = {$sort:{}}

解开数组

// 使用project可以解开嵌入文档
var 查询条件 = {gender:0}
var 返回条件 = {_id:0, '身高':'$body.height'}
//var 返回条件 = {_id:0, 'body.height':1}
var 步骤1 = {$match:查询条件}   // 查询出所有的女生
var 步骤2 = {$project:返回条件} // 的身高
db.stu.aggregate([步骤1, 步骤2])
// 使用unwind解开数组
db.test.insert(
{
    'name':'tanguangyu',
    'hobit':['reading','football','pingpong']
}
)
db.test.find({name:'tanguangyu'})

返回的是一个嵌入式文档或者数组,这并不是我们需要的东西

image.png

db.test.aggregate([{$unwind:'$hobit'}])

这才是我们需要的东西

image.png

// 统计分布式数据库课程的平均分
var 解开courses = {$unwind:'$courses'}
var 筛选分布式课程记录 = {$match:{'courses.course':/分布式/}}
var 统计成绩的平均值 = {$group:{_id:'$courses.course', '平均分':{$avg:'$courses.score'}}}
var 批处理 = [解开courses,筛选分布式课程记录,统计成绩的平均值]
db.stu.aggregate(批处理)
// 统计所有课程的平均分
var 解开courses = {$unwind:'$courses'}
var 统计成绩的平均值 = {$group:{_id:'$courses.course', '平均分':{$avg:'$courses.score'}}}
var 批处理 = [解开courses,统计成绩的平均值]
db.stu.aggregate(批处理)
var 解开courses = {$unwind:'$courses'}
var 统计成绩的平均值 = {$group:{_id:'$courses.course', '平均分':{$avg:'$courses.score'}}}
var 重命名Id字段 = {$project:{_id:0,'课程名':'$_id','平均分':1}}
var 筛选分布式课程 = {$match:{'课程名':/分布式/}}
var 批处理 = [解开courses,统计成绩的平均值,重命名Id字段,筛选分布式课程]
db.stu.aggregate(批处理)
var 解开courses数组 = {$unwind:'$courses'}
var 解开courses文档 = {$project:{_id:0,'课程名':'$courses.course','课程成绩':'$courses.score'}}
var 统计成绩的平均值 = {$group:{_id:'$课程名', '平均分':{$avg:'$课程成绩'}}}
var 重命名Id字段 = {$project:{_id:0,'课程名':'$_id','平均分':1}}
var 筛选分布式课程 = {$match:{'课程名':/分布式/}}
var 批处理 = [解开courses数组,解开courses文档,统计成绩的平均值,重命名Id字段,筛选分布式课程]
db.stu.aggregate(批处理)

对于数组的操作,我们想要把它解开进行操作,我们就可以使用这个方法进行操作,然后利用批处理的框架进行思维构造,这样就不会不知道怎么去写了

总结

1.拿到一个实际问题,我们首先要把问题放在数据集里面进行思考,考虑这个问题到底是什么,在数据里面应该处于哪一个位置,我们应该如何去构建我们的语法


2.批处理框架要学会搭建,这样就不会写代码的时候过于的考虑这一个代码是不是会导致我们的数据查询不完整


3.需不需要解开数组,需要的话,我们就可以利用  var 解开数组 ={$unwind:'数组的顶端'},然后再去考虑你要的数据集,也就是我们所说的解开文档,利用   var 解开文档={$project:{_id:0,'新字段名':‘旧字段名值’}},其实这样做的目的是为了把我们的字段名进行一个解开的操作


4.然后我们利用group进行聚合或者分组,也可以进行相关的集合操作


5.进行字段的重命名,这个时候就是真正的需要我们规范化的命名了


6.最后再来一个筛选,看你是否需要这个,按照自己的实际场景结合


7.批处理的列表,将上述的所有变量步骤,放进去即可


8.db.collection.aggregate(批处理)



如果说步骤有这么多的话,那么我们也可以按照自己的想法和需求进行,比如对于在嵌入式的文档操作里面,一般都会有数组的类型,那么我们是不是要考虑解开数组,然后在解开数组里面的文档,再其次我们就可以进行group里面的分组和集合运算了,之后我们可以考虑我们要不要去重命名这个字段,方便与我们下一步的操作,也就是我们要显示的字段,最后在一个大的数据集里面我们想要再去缩小一下范围,我们就可以考虑一下是不是需要利用正则表达式或者其他方法来,缩减我们的数据查询范围。


总之我们在进行MongoDB里面的数据集查询时候,要想事半功倍一定要有一个模板框架和思维数据,不然就会是“竹篮打水一场空”

// 分班级计算分布式课程不及格的学生人数
// 步骤1, 先找到全校选了分布式数据库课程,而且成绩小于60的学生
//    a: 解开课程数组
//    b: 为了好看,解开课程嵌入文档
//    c: 查找课程名和成绩
// 步骤2, 然后在上面的结果中分班统计数量
//    a: 为了好看,解开_id文档
//    b: 为了好看,排个序
var 步骤1a = {$unwind : "$courses"}
var 步骤1b = {$project : {_id:0,'major':1,'grade':1,'class':1,'coursename':'$courses.course', 'coursescore':'$courses.score'}}
var 步骤1c = {$match : {'coursename':/分布式数据库/, 'coursescore':{$lt:60}}}
var 步骤2 = {$group : {'_id':{'major':"$major",'grade':"$grade",'class':"$class"}, 人数:{$sum:1}}}
var 步骤2a = {$project : {_id:0,专业:"$_id.major",年级:"$_id.grade",班级:"$_id.class",分布式数据库不及格人数:"$人数"}}
var 步骤2b = {$sort : {"专业":1,"年级":1,"班级":1}}
var 步骤列表 = [步骤1a,步骤1b,步骤1c,步骤2,步骤2a,步骤2b]
db.getCollection("stu").aggregate(步骤列表)
相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
26天前
|
SQL NoSQL Unix
MongoDB 聚合
10月更文挑战第17天
19 4
|
2月前
|
SQL NoSQL Unix
MongoDB聚合操作总结
这篇文章总结了MongoDB中聚合操作的作用、方法、常见聚合表达式以及聚合管道的概念和常用操作符,以及SQL与MongoDB聚合操作的对应关系。
41 2
MongoDB聚合操作总结
|
26天前
|
SQL NoSQL 数据处理
深入探索MongoDB的聚合操作
【10月更文挑战第13天】
13 0
|
2月前
|
NoSQL MongoDB 数据库
python3操作MongoDB的crud以及聚合案例,代码可直接运行(python经典编程案例)
这篇文章提供了使用Python操作MongoDB数据库进行CRUD(创建、读取、更新、删除)操作的详细代码示例,以及如何执行聚合查询的案例。
33 6
|
2月前
|
SQL NoSQL JavaScript
04 MongoDB各种查询操作 以及聚合操作总结
文章全面总结了MongoDB中的查询操作及聚合操作,包括基本查询、条件筛选、排序以及聚合管道的使用方法和实例。
75 0
|
3月前
|
持续交付 jenkins Devops
WPF与DevOps的完美邂逅:从Jenkins配置到自动化部署,全流程解析持续集成与持续交付的最佳实践
【8月更文挑战第31天】WPF与DevOps的结合开启了软件生命周期管理的新篇章。通过Jenkins等CI/CD工具,实现从代码提交到自动构建、测试及部署的全流程自动化。本文详细介绍了如何配置Jenkins来管理WPF项目的构建任务,确保每次代码提交都能触发自动化流程,提升开发效率和代码质量。这一方法不仅简化了开发流程,还加强了团队协作,是WPF开发者拥抱DevOps文化的理想指南。
82 1
|
3月前
|
NoSQL BI 数据处理
【超实用攻略】MongoDB 聚合框架:从入门到精通,带你解锁数据处理新姿势!
【8月更文挑战第24天】MongoDB是一款以其灵活性和高性能闻名的NoSQL数据库。其强大的聚合框架采用管道式处理,允许用户定义多个数据处理阶段如过滤、分组等。本文通过示例数据库`orders`和`products`,演示如何利用聚合框架计算各产品的总销售额。示例代码展示了使用`$lookup`连接两集合、`$unwind`打平数组及`$group`按产品ID分组并计算总销售额的过程。这突显了聚合框架处理复杂查询的强大能力,是进行数据分析和报表生成的理想选择。
51 3
|
3月前
|
存储 NoSQL JavaScript
MongoDB存储过程实战:聚合框架、脚本、最佳实践,一文全掌握!
【8月更文挑战第24天】MongoDB是一款备受欢迎的文档型NoSQL数据库,以灵活的数据模型和强大功能著称。尽管其存储过程支持不如传统关系型数据库,本文深入探讨了MongoDB在此方面的最佳实践。包括利用聚合框架处理复杂业务逻辑、封装业务逻辑提高复用性、运用JavaScript脚本实现类似存储过程的功能以及考虑集成其他工具提升数据处理能力。通过示例代码展示如何创建订单处理集合并定义验证规则,虽未直接实现存储过程,但有效地演示了如何借助JavaScript脚本处理业务逻辑,为开发者提供更多实用指导。
69 2
|
3月前
|
存储 NoSQL 数据处理
【MongoDB大神级操作】揭秘聚合框架,让你的数据处理能力瞬间飙升,秒变数据界的超级英雄!
【8月更文挑战第24天】MongoDB是一款备受欢迎的非关系型数据库,以其灵活的文档模型和出色的可扩展性著称。其聚合框架尤其亮眼,能高效地对数据库中的数据执行复杂的转换与聚合操作,无需将数据导出到应用端处理,极大提升了数据处理的效率与灵活性。例如,在一个大型电商数据库中,聚合框架能轻松分析出最热卖的商品或特定时段内某类别商品的销售总额。通过一系列管道操作,如$unwind、$group等,可以对数据进行逐步处理并得到最终结果,同时还支持过滤、排序、分页等多种操作,极大地丰富了数据处理的能力,成为进行数据分析、报表生成及复杂业务逻辑实现的强大工具。
73 2
|
3月前
|
持续交付 jenkins C#
“WPF与DevOps深度融合:从Jenkins配置到自动化部署全流程解析,助你实现持续集成与持续交付的无缝衔接”
【8月更文挑战第31天】本文详细介绍如何在Windows Presentation Foundation(WPF)项目中应用DevOps实践,实现自动化部署与持续集成。通过具体代码示例和步骤指导,介绍选择Jenkins作为CI/CD工具,结合Git进行源码管理,配置构建任务、触发器、环境、构建步骤、测试及部署等环节,显著提升开发效率和代码质量。
76 0