MongoDB 挑战传统数据库聚合查询,干不死他们的

开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,(共2280人左右 1 + 2 + 3 + 4 +5) 新人奖直接分配到5群,5群即将达到400,停止自由申请 已建立6群。

f31df4e70bc7a86726d0fd85ab6fc880.png

说句不怕笑话的话,MongoDB使用也有6 7 8 年了,但对于聚合一般我是抗拒的,可能是MOGNODB 3.X落下的顽疾,一听到用MongoDB 做聚合操作,一般都不想听 不想听。但时代不一样,MongoDB已经走到了 8.0UP,聚合早就和之前不一样了。

所以怕也的上,还的学习。 以上学习基于MOGNODB7.0 ,聚合操作中首选的方案是聚合管道,或者使用单一聚合的方法。一般来说聚合操作中的管道操作,主要是通过多个阶段来处理数据,比如第一需要先过滤数据,然后对过滤的数据进行文档的分组并计算聚合操作后的结果。同时聚合还可以进行聚合后的数据更新,当然这需要在4.2后的版本才有此功能。

我们先产生测试数据,先简单产生 4万条数据

mongo7 [direct: primary] test> function insertData(dbName, colName, num) {
... 
...   var col = db.getSiblingDB(dbName).getCollection(colName);
... 
...   for (i = 0; i < num; i++) {
...     col.insert({x:i});
...   }
... 
...   print(col.count());
... 
... }
[Function: insertData]
mongo7 [direct: primary] test> insertData("test", "testData", 40000)
DeprecationWarning: Collection.insert() is deprecated. Use insertOne, insertMany, or bulkWrite.
DeprecationWarning: Collection.count() is deprecated. Use countDocuments or estimatedDocumentCount.
40000

52a18c62603b37323d6d9b6aee533bd7.png

下面我们开始,假设一个需求,我需要计算插入数据中 10000 到 20000 ,20000 到 30000 之间的数据值的累加和并展示出来。

mongo7 [direct: primary] test> db.testData.aggregate([
...   {
...     $match: { 
...       x: { $gte: 10000, $lt: 30000 }
...     }
...   },
...   {
...     $group: {
...       _id: null,
...       sum1: { $sum: { $cond: [{ $and: [ { $gte: ["$x", 10000] }, { $lt: ["$x", 20000] } ] }, "$x", 0] } },
...       sum2: { $sum: { $cond: [{ $and: [ { $gte: ["$x", 20000] }, { $lt: ["$x", 30000] } ] }, "$x", 0] } }
...     }
...   }
... ])
[ { _id: null, sum1: 149995000, sum2: 249995000 } ]
mongo7 [direct: primary] test>

上面的语句,直接将结果进行了计算和展示非常快。

首先这边语句分为两个部分,第一部分是限制数据进入,因为这里计算是大于等于10000 和 小于30000,所以我们需要根据match 来进行数据的排除,将9999以内的数字和30000以外的数据进行,排除。

 $match: { x: { $gte: 10000, $lt: 30000}

然后留下的是我们的要处理的数据,进行数据的聚合操作。

 $group: {

      _id: null,

      sum1: { $sum: { $cond: [{ $and: [ { $gte: ["$x", 10000] }, { $lt: ["$x", 20000] } ] }, "$x", 0] } },

      sum2: { $sum: { $cond: [{ $and  [ { $gte: ["$x", 20000] }, { $lt: ["$x", 30000] } } }, "$x", 0] } }

这里在过滤出我们要的数据后,首先我们遇到的是针对什么进行分组,如果是传统数据库,这里面一般就头疼了,分组是没有字段的,这里MongoDB 是可以针对没有分组的聚合数据进行分组的,上面就是一个案例,我们只有object_id  , x 两个字段,我们怎么聚合分组我们的分组实际是值,这也是传统DBA 烧脑的开始。

我们这里根据过滤出的条件,分别对于符合条件的数据进行聚合。

 sum1: { $sum: { $cond: [{ $and: [ { $gte: ["$x", 10000] }, { $lt: ["$x", 20000] } ] }, "$x", 0] } }

这条的意思是,首先要表达的是我们要进行 sum的操作,也就是累加和,然后 cond 的意思是在我们match后的数据还需要进行条件的筛选,也就是我这里只要大于等于10000 和小于20000的数,进行累加和,如果这里条件都不符合的话,我们就给一个默认的值 0 

mongo7 [direct: primary] test> db.testData.aggregate([
...   {
...     $match: { 
...       x: { $gte: 10000, $lt: 30000 }
...     }
...   },
...   {
...     $group: {
...       _id: null,
...       sum1: { $sum: { $cond: [{ $and: [ { $gte: ["$x", 10000] }, { $lt: ["$x", 20000] } ] }, "$x", 0] } },
...       sum2: { $sum: { $cond: [{ $and: [ { $gte: ["$x", 20000] }, { $lt: ["$x", 30000] } ] }, "$x", 0] } },
...       sum3: { $sum: { $cond: [{ $and: [ { $gte: ["$x", 40000] }, { $lt: ["$x", 50000] } ] }, "$x", 0] } }
...     }
...   }
... ])
[ { _id: null, sum1: 149995000, sum2: 249995000, sum3: 0 } ]
mongo7 [direct: primary] test>

上面的例子中我们可以看到,最后一句明显就是找茬的,我们在顾虑数据的时候值包含了10000 到 30000的数据,而下面是要40000到50000的数据,这里cond 条件就产生效用了,如果符合条件则打印结果,如果不符合条件,则选择后面的给定的结果进行打印,很明不符合条件的为0 

那么这样的语句还有其他的写法吗,有的,例如下面的写法

mongo7 [direct: primary] test> db.testData.aggregate( [
...    {
...       $match: { x: { $gte: 10000, $lt: 30000}  }
...    },
...  {
...     $group: {
...       _id: null,
...       sum1: { $sum: { $cond: [{ $and: [ { $gte: ["$x", 10000] }, { $lt: ["$x", 20000] } ] }, "$x", 0] } },
...       sum2: { $sum: { $cond: { if: { $gte: ["$x", 20000] }, then: "$x", else: 0 } } }
...     }
...   }
... ] )
[ { _id: null, sum1: 149995000, sum2: 249995000 } ]
mongo7 [direct: primary] test>

我们可以看到,结果是一样的,但写法的确是不同,第二个我们采用了是条件的方式来撰写的,也就是最后一个20000到3000,所以用了另一种Mongodb的语句的写法。

 sum2: { $sum: { $cond: { if: { $gte: ["$x", 20000] }, then: "$x", else: 0 } } }

这个写法的意思是,如果值大于等于20000的话,那么就取值,否则就是0 

明显这里是一个判断的方式的表达,如果想用SQL 来表达类似的意思可以写成,下图方式

SELECT
    NULL AS _id,
    SUM(CASE WHEN x >= 10000 AND x < 20000 THEN x ELSE 0 END) AS sum1,
    SUM(CASE WHEN x >= 20000 AND x < 30000 THEN x ELSE 0 END) AS sum2,
    SUM(CASE WHEN x >= 40000 AND x < 50000 THEN x ELSE 0 END) AS sum3
FROM
    testData
WHERE
    x >= 10000 AND x < 30000;

最后在给传统数据库DBA 来一个烧脑的作为此次的结尾,这样的数据查询如果是在传统数据库,相比是有索引也走不了,作为传统的DBA 对于这样的语句,在X列加索引,是不会抱有希望的。

这里我们也比较一下,在对X key 加索引后的查询执行计划,是否有不同,答案是当然有不同。

1 不加索引,时从执行计划看,走了全collection扫描是没跑了

fac69c2eaff5858902ad4a6bb2a8a75e.png

2 添加索引后

278d9b693de95bf4aeb90f5b504df535.png

结果与传统数据库的思路不一样,传统思路这样的查询这样的量是无法走索引的,全表扫描是一定的,而在NOSQL数据库中,这样的情况添加了索引也可以运行并使用,后续还的学习和发现,目前写不下去了,需要散热

后记,随着文档型数据库的被熟知,并且步步紧逼传统数据库一些事务,跨表,跨库查询,以及聚合查询等方案的退出,以及天然的分布式存储方式,和传统数据库打死都没有的灵活性,文档数据库和传统型数据库PK 的还在后面。

待.....

今天本账号同时发售

bf11da9f3282933f2ec3f776c313e3fe.png

置顶

临时工访谈:无名氏意外到访-- 也祝你好运(管理者PUA DBA现场直播)

临时工说:搞数据库 光凭的是技术,那DBA的死多少次?

往期热门文章:

PostgreSQL  分组查询可以不进行全表扫描吗?速度提高上千倍?

临时工说:分析当前经济形势下 DBA 被裁员的根因

JunkFood读者说你文章不对,作者被鞭策后,DBA 开始研究JAVA程序锁

PostgreSQL PG_DUMP 工作失败了怎么回事及如何处理

MySQL 八怪(高老师)现场解决问题实录

临时工说:经济规律解读ORACLE 工资低   --读 Roger 数据库专栏

PostgreSQL 为什么也不建议 RR隔离级别,MySQL别笑

临时工访谈:OceanBase上海开大会,我们四个开小会 OB 国产数据库破局者

临时工说:OceanBase 到访,果然数据库的世界很卷,没边

临时工访谈:恶意裁员后,一个国产数据库企业程序员的心声

临时工访谈:国产数据库裁员失业中,但我仍然积极乐观的DBA

临时工访谈:45岁IT女领导 失业 后的人生下半部

临时工访谈:TM 这些年 我都培训了什么

临时工说:上云后给 我一个 不裁 DBA的理由

临时工说:腾讯云,阿里云故障  “核爆炸”  后持续的影响

临时工说:三次封禁后的文章--技术文章怎么写,我有罪

PolarDB for PostgreSQL  有意思吗?有意思呀

PostgreSQL   玩PG我们是认真的,vacuum 稳定性平台我们有了

临时工说:裁员裁到 DBA 咋办  临时工教你 套路1 2 3

PolarDB  搞那么多复杂磁盘计费的东西,抽筋了吗?

临时工说:OceanBase 到访,果然数据库的世界很卷,没边

MONGODB  ---- Austindatabases  历年文章合集

MYSQL  --Austindatabases 历年文章合集

POSTGRESQL --Austindatabaes 历年文章整理

POLARDB  -- Ausitndatabases 历年的文章集合

PostgreSQL  查询语句开发写不好是必然,不是PG的锅

SQL SERVER 如何实现UNDO REDO  和PostgreSQL 有近亲关系吗

MongoDB 2023纽约 MongoDB 大会 -- 我们怎么做的新一代引擎 SBE Mongodb 7.0双擎力量(译)

MongoDB 2023年度纽约 MongoDB 年度大会话题 -- MongoDB 数据模式与建模

MongoDB  双机热备那篇文章是  “毒”

MongoDB   会丢数据吗?在次补刀MongoDB  双机热备

临时工说:从人性的角度来分析为什么公司内MySQL 成为少数派,PolarDB 占领高处

POLARDB  到底打倒了谁  PPT 分享 (文字版)

PostgreSQL  字符集乌龙导致数据查询排序的问题,与 MySQL 稳定 "PG不稳定"

PostgreSQL  Patroni 3.0 新功能规划 2023年 纽约PG 大会 (音译)

Austindatabases 公众号,主要围绕数据库技术(PostgreSQL, MySQL, Mongodb, Redis, SqlServer,PolarDB, Oceanbase 等)和职业发展,国外数据库大会音译,国外大型IT信息类网站文章翻译,等,希望能和您共同发展。

截止今日共发布 1134 篇文章

e08cf7b85460725215a4debce229a51f.png

71db026a29fb698c4942394b9d5a7761.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值