您的位置:首页 > 游戏 > 手游 > 【Mongodb-04】Mongodb聚合管道操作基本功能

【Mongodb-04】Mongodb聚合管道操作基本功能

2024/11/18 5:31:48 来源:https://blog.csdn.net/zhenghuishengq/article/details/140402214  浏览:    关键词:【Mongodb-04】Mongodb聚合管道操作基本功能

Mongodb系列整体栏目


内容链接地址
【一】Mongodb亿级数据性能测试和压测https://zhenghuisheng.blog.csdn.net/article/details/139505973
【二】springboot整合Mongodb(详解)https://zhenghuisheng.blog.csdn.net/article/details/139704356
【三】亿级数据从mysql迁移到mongodb辛酸历程https://zhenghuisheng.blog.csdn.net/article/details/140302930
【四】Mongodb聚合管道操作基本功能https://zhenghuisheng.blog.csdn.net/article/details/140402214

mongodb聚合操作基本功能

  • 一,mongodb聚合操作基本功能
      • 1,单一聚合
      • 2,聚合管道 + 聚合操作符
        • 2.1,Count
        • 2.2,SUM
        • 2.3,Group By
        • 2.4,分组+排序
        • 2.5,多字段分组+时间格式化
        • 2.6,Group By + Having
        • 2.7,Where
        • 2.8,子查询
        • 2.9,分页
        • 2.10,连表查询

一,mongodb聚合操作基本功能

在mysql中,允许一些匹配,分组,排序,分页,求和以及多表之间的连表操作,在mongodb中,这些操作也是可以实现的,内部就是通过聚合操作实现。在mongodb中,聚合操作主要有三大类操作,分别是: 单一作用聚合、聚合管道、MapReduce ,在mongodb5.0开始,mapReduce被废弃,因为能通过MapReduce实现的功能,都可以通过这个聚合管道实现,并且聚合管道的效率还远高于MapReduce,因此本文主要是了解单一管道和聚合管道。

在了解聚合管道之前,可以先通过官方文档的教程以及如何使用:mongodb聚合管道的使用

管道的模型如下,其设计理念就是通过流水线的模式,每一个步骤处理一个操作,,每一个步骤处理完的结果传给下一个步骤,最后将结果给返回

请添加图片描述

在官网中,给了一个 sql-聚合 的映射图标,通过sql中的语法和者术语来更加清楚的了解 聚合操作的概念和使用

请添加图片描述

1,单一聚合

假设此时有一张orders的订单集合,类似于mysql中的orders订单表,在mongodb中对这些单一聚合提供了简单访问,如以下获取文档的总个数,去重等,纯原生的方式实现数据的获取,在性能上没有聚合管道的效率高

db.orders.estimatedDocumentCount(),  
db.orders.countDocument(),
db.orders.distinct()

2,聚合管道 + 聚合操作符

在官方文档中给了很多的聚合阶段的方式,接下来主要是结合官方提供的映射图标的文档,来理解mongodb中常用的一些聚合方式。在讲解聚合管道之前,先提供一些mongodb内部的一些操作符,类似于mysql的一些聚合函数,如比较操作符,日期操作符,算术表达式操作符等等。通过管道再结合对应的操作符,来实现对文档的查询,从而使得mongodb可以和关系型数据库一样的操作流程,并通过json的数据格式,让整个查询更加的灵活

在这里插入图片描述

2.1,Count

在mysql中,计算一张表的数据有多少条,可以直接使用 count(*) 命令

select count(*) as count from orders

在mongodb中聚合管道的操作命令如下,_id为空就是表示不根据某个字段进行分组,即所有文档在同一个组里面,里面的 {$sum:1} 表示的是一个累计计数器的效果,表示查询出文档的条数,这里的每有一条文档那么这个计数器就会加1。比如查询出来是100条,那么count的值就是100,和上面mysql的as count的操作是一样的

db.orders.aggregate([{$group:{_id:null,count:{$sum:1}}}
])
2.2,SUM

对于mysql的求和统计操作,一般都是通过sum聚合函数实现,如查看订单表中的总价格的和

SELECT SUM(price) AS total FROM orders

在moogodb中的实现也可以如下,管道结合 $sum 操作符实现,这里和上面的一样,只是在sum求和时携带的参数不一样,上面的值设置的是1,下面的值设置的是每条文档中具体的某个字段的值,因此可以统计出所有订单的汇总价格

db.orders.aggregate([{$group:{_id:null,total:{$sum:"$price"}}}   
])
2.3,Group By

在上面虽然也用了group by,但是在 _id 那个字段并没有设置对应文档中的字段,在实际情况看到会有根据某个字段先分组早再求和的情况,如根据用户id进行分组再进行求和

select user_id,sum(price) as total from orders group by user_id

结合上面的1,2两点,可以得知上面的mysql的效果实现如下,让_id 字段设置成要分组的字段即可

db.orders.aggregate([{$group:{_id:"$user_id",total:{$sum:"price"}}}
])
2.4,分组+排序

在订单表中,要查出每一个用户下单花费的总金额,并通过从大到小的方式进行排序

select user_id,sum(price) as total from orders group by user_id order by total

mongodb的实现如下,这里需要两个聚合操作,将上一个聚合操作的结果给下一个聚合操作,在sort聚合函数中,1表示升序,2表示降序

db.orders.aggregate([{$group:{_id:"$user_id",total:{$sum,"$price"}}},{$sort:{total:1}}
])
2.5,多字段分组+时间格式化

就是需要通过user_id+每天的进行分组,统计每个用户每天消费了多少

select user_id,date_format(created_at,'%y-%m-%d') as order_date,sum(price)
from orders
group by user_id,date_formate(created_at,'%-y-%m-%d')    

mongodb的聚合操作如下,如果有多个分组字段,那么就在 _id 对象中设置多个参数,并且按照从上往下的顺序设置,使用日期表达式操作符将时间进行格式化

db.orders.aggregate([{$group:{_id:{user_id:"$user_id",order_date: { $dateToString: {format: "%Y-%m-%d",date: "$created_at"}}},total:{$sum:"price"}}}
])
2.6,Group By + Having

比如返回用户消费大于1000的用户信息,mysql的语法如下

select user_id,sum(price) as total from orders group by user_id having total > 1000

使用mongodb聚合操作的语法如下,通过match聚合命令匹配实现,并且结合gt的比较运算符进行数据的过滤,最后将对应的文档返回

db.orders.aggregate([{$group:{_id:"user_id",total:{$sum:"$price"}}},{$match:{total:{count:{$gt:1000}}}}
])
2.7,Where

比如返回订单表中商品id为10001的商品,并且差每个人花费的总金额,按降序排序

select user_id,sum(price)as total from orders where product_id = 10001 group by user_id order by total

使用mongodb的聚合操作的语法如下,期语法罗伊和mysql的一样,先过滤,再分组,再排序

db.orders.aggregate([{$match:{product_id:10001},$group:{_id:"$user_id",total:{$sum:"$price"}},{$sort:{total:1}}}
])
2.8,子查询

比如查询一个简单的,查询订单表中总共有多少用户下单(用户去重)

SELECTCOUNT(*)
FROM (SELECT user_id FROM orders GROUP BY user_id) t

通过mongodb举个查询的语法如下,只需要通过两个group就能实现,在第二个group中将id值设置为null

db.orders.aggregate([{$group:{_id:"$user_id",total:{$sum:"$price"}}},{$group:{_id:null,count: { $sum: 1 }}}
])
2.9,分页

在mysql中,分页查询直接通过limit即可,如查询订单表中商品id为10001的花费最多的钱10名的用户

selectuser_id,sum(price) as total
from orders
where product_id = 10001
group by user_id 
order by total desc limit 10

在mongodb的聚合管道中,其实现方式也比较简单,只需要多聚合几个条件即可,先执行where条件的管道,然后分组管道,排序管道,分页管道,最终将数据返回,通过数据库层面实现数据的过滤和查询,从而减少网络io传输

db.orders.aggregate([{$match:{product_id,10001},},{$group:{_id:"$user_id",total:{$sum:"$price"}}},{$sort:{total:-1}},{$limit:10}
])
2.10,连表查询

在mysql中,查询商品id为10001的花费最多的钱10名的用户的用户名

selectu.name,order.user_id,sum(order.price) as total
from orders order
left join user u on u.id = order.user_id
where order.product_id = 10001
group by order.user_id 
order by total desc limit 10

通过mongodb聚合渠道的方式如下,通过$lookup 关键字来实现联表,from表示需要连接的那张表,localField表示主表中需要关联的字段,foreignField表示需要关联的那张表中要关联的字段,最活通过一个 unwind 关键字将数组的值展开,让每一个订单表中查询出来的数据对应一个用户信息,最后再通过增加一个分组,排序和分页的聚合操作

db.orders.aggregate([{ $match: { product_id: 10001 } },  // 筛选出 product_id 为 10001 的订单{ $lookup: {                       // 左外连接用户表from: "users",                 // 'users' 集合(假设用户集合名称为 users)localField: "user_id",         // orders 集合中连接键foreignField: "id",            // users 集合中连接键as: "user_info"                // 查询结果的新字段名}},{ $unwind: "$user_info" },         // 展开连接结果,使每个订单对应一个用户信息{ $group: {                        // 分组操作_id: "$user_id",               // 根据 user_id 分组name: { $first: "$user_info.name" },  // 从用户信息中获取名字total: { $sum: "$price" }              // 计算总金额}},{ $sort: { total: -1 } },          // 按 total 降序排序{ $limit: 10 }                     // 限制结果为前 10 条
]);

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com