MongoDB Aggregation 聚合框架

MongoDB Aggregation 聚合框架

前言

本章主要讨论以下几点

  • 介绍 MongoDB Aggregation 聚合框架相关的概念和基础知识
  • MQL(MongoDB 脚本语言)与 SQL 进行类比
  • MongoDB Compass(推荐工具)介绍
  • 结合实际项目功能演示 Spring Data MongoDB

1.MongoDB 聚合框架是什么

MongoDB 聚合框架(Aggregation Framework)是一个计算框架,它可以:

  • 作用在一个或几个集合上
  • 对集合中的数据进行的一系列运算
  • 将这些数据转化为期望的形式

从效果而言,聚合框架相当于 SQL 查询中的

  • GROUP BY
  • LEFT OUTER JOIN
  • AS

2.管道(Pipeline)和步骤(Stage)

整个聚合运算过程称为管道(Pipeline),它是由多个步骤(Stage)组成的,每个管道:

  • 接收一系列文档(原始数据)
  • 每个步骤对这些文档进行一系列运算
  • 结果文档输出给下一个步骤
  • 直到输出最终结果

image-20210308171537360.png

3.聚合运算的基本格式

pipeline = [$stage1,$stage2,$stage3...];

db.<collection_name>.aggregate(
   pipeline,
   {options}
);

4.步骤

步骤作用SQL 等价运算符
$match过滤where
$project投影as
$sort排序order by
$group分组group by
$skip/$limit结构限制skip/limit
$lookup左外连接left outer join
$unwind展开数组
$graphLookup图搜索
$facet/$bucket分面搜索

5.步骤中的运算符

5.1 $match

类似于 where,匹配条件

  • $eq/$gt/$gte/$lt/$lte
  • $and/$or/$not/$in
  • $geoWithin/$intersect

5.2 $project

类似于 as,设置别名

  • 选择需求的或者排除不需要的字段
  • $map/$reduce/$filter
  • $range
  • $multiply/$divide/$substract/$add
  • $year/$month/$dayOfMonth/$hour/$minute/$second

5.3 $group

类似于 group by 分组

  • $sum/$avg
  • $push/$addToSet
  • $first/$last/$max/$min

6.MQL & SQL 对比

6.1 例1

SQL:

SELECT 
    NAME AS '名称',
	age AS '年龄' 
FROM
	users 
WHERE
	gender = '男' 
	skip 100 
	LIMIT 20

MQL :

db.users.aggregate([
    // 步骤1:匹配性别
    {
        $match: {
            gender: "男"
        }
    },
    // 步骤2:跳过前100
    {
        $skip: 100
    },
    // 步骤3:取20个
    {
        $limit: 20
    },
    // 步骤4:设置别名
    {
        $project: {
            "名称": "$name",
            "年龄": "$age"
        }
    }
])

6.2 例2

SQL:

SELECT
	department,
	count(*) AS count 
FROM
	users 
WHERE
	gender = '男' 
GROUP BY
	department 
HAVING
	count(*)< 10

MQL:

db.users.aggregate([
    // 步骤1:条件匹配
    {
        $match: {
            gender: "男"
        }
    },
    // 步骤2:分组求和
    {
        $group: {
            _id: "$department",
            count: {
                $sum: 1
            }
        }
    },
    // 步骤3:根据上一步的 count 条件匹配
    {
        $match: {
            count: {
                $lt: 10
            }
        }
    }
])

7.特殊步骤

7.1 $unwind

普通查询:

在这里插入图片描述

使用 $unwind 之后,将数组拆分成三条数据显示

在这里插入图片描述

7.2 $bucket

在这里插入图片描述

按年龄进行分组,原始数据如下:

在这里插入图片描述

MQL:

db.getCollection("users").aggregate([{
    $bucket: {
        groupBy: "$age",
        boundaries: [0, 10, 20, 30, 40, 50],
        default: "Other",
        output: {
            output: {
                $sum: 1
            }
        }
    }
}])

在 MongoDB Compass(下面会提到这个工具) 中看到的结果如下:

在这里插入图片描述

7.3 $facet

在这里插入图片描述

在上面的基础上增加一个薪水(salary)字段

在这里插入图片描述

MQL:

db.getCollection("users").aggregate([{
    $facet: {
        age: [{
            $bucket: {
                groupBy: "$age",
                boundaries: [0, 10, 20, 30, 40, 50],
                default: "Other",
                output: {
                    output: {$sum: 1}
                }
            }
        }],
        salary: [{
            $bucket: {
                groupBy: "$salary",
                boundaries: [0, 5000, 7000, 8000, 10000],
                default: "Other",
                output: {
                    output: {$sum: 1}
                }
            }
        }]
    }
}])

在 MongoDB Compass (下面会提到这个工具)中看到的结果如下:
在这里插入图片描述

8.MongoDB Compass(推荐工具)

官网下载地址:https://www.mongodb.com/products/compass

8.1 基本使用

6.2 例2 为例

选择对应的集合 users 和 Aggregations

在这里插入图片描述

选择步骤,这里我们选择 $match

在这里插入图片描述

每写一个条件,会实时显示当前步骤产生的中间结果

在这里插入图片描述

8.2 导出

全部写完成之后,点击导出按钮

在这里插入图片描述

左边是 MQL,右边可以选择导出的语言类型

在这里插入图片描述

9.Spring Data MongoDB

官网地址:https://docs.spring.io/spring-data/mongodb/docs/3.1.5/reference/html/#reference

搜索 Aggregation 关键字即可找到对应的文档。

下面两个示例是实际项目的代码,进行了一定的处理

9.1 按日期求和

MQL:

db.xxx_log.aggregate(
    [{
		//步骤1:对 operate_time 时间字段进行截取,设置别名 operate_day
        $project: {
            "operate_day": {
                $substrCP: ['$operate_time', 0, 10]
            }
        }
    }, {
		//步骤2:分组
        $group: {
            _id: "$operate_day",
            count: {
                $sum: 1
            },
            operate_day: {
                $first: "$operate_day"
            }
        }
    }, {
		//步骤3:排序
        $sort: {
            "operate_day": 1
        }
    }]
);

Spring 中对应的代码

    Aggregation agg = Aggregation
        .newAggregation(
            // 步骤1:显示字段
            project().and("operate_time").substring(0, 10).as("operate_day"),
            // 步骤2:分组
            group("operate_day").count().as("count").
            first("operate_day").as("operateDay"),
            // 步骤3:排序
            sort(Direction.ASC, "operateDay"));

    AggregationResults<XXXLogGroupDay> result = operations
        .aggregate(agg, "xxx_log", XXXLogGroupDay.class);
    return result.getMappedResults();

XXXLogGroupDay 实体类

@Data
public class XXXLogGroupDay {

  private String operateDay;

  private Integer count;

}

9.2 多字段分组,查询每天的情况

MQL

db.image_analyze_log.aggregate(
  // 步骤1:截取字段,设置部分字段别名
[{$project: {
   "operate_day": { $substrCP: ['$operate_time', 0, 10] },
   "pass":"$pass",
   "failureReason":"$failureReason"
  }}, 
 // 步骤2:分组
 {$group: {
  // 按 operate_day 和 pass 两个属性进行分组
  _id: {operate_day:"$operate_day",pass:"$pass"},
  operate_day:{$first:"$operate_day"},
  // 取第一个值显示 
  pass:{$first:"$pass"},
  // 将字段推送到一个数组中
  failureReason:{$push:"$failureReason"},
  count: {$sum: 1},
  }}, 
 // 步骤3:排序
 {$sort: {
  "operate_day": 1
}}]
)

Spring 中对应的代码

    Aggregation agg = Aggregation
        .newAggregation(
            // 步骤1:显示字段
            project().and("operate_time").substring(0, 10).as("operate_day")
                .and("analyze_result.qualityCheckResult.pass").as("pass")
                .and("analyze_result.qualityCheckResult.failureReason").as("failureReason"),
            // 步骤2:分组
            group("operate_day", "pass").count().as("count").
                push("failureReason").as("failureReason").
                first("pass").as("pass").
                first("operate_day").as("operateDay"),
            // 步骤3:排序
            sort(Direction.ASC, "operateDay"));

    AggregationResults<XXXLogGroupDay> result = operations
        .aggregate(agg, "xxx_log", XXXLogGroupDay.class);
    return result.getMappedResults();

返回结果:

{
  "code": 0,
  "msg": "成功",
  "data": [
    {
      "operateDay": "2021-03-04",
      "pass": "true",
      "count": 666,
      "failureReason": []
    },
    {
      "operateDay": "2021-03-04",
      "pass": "false",
      "count": 10,
      "failureReason": [
        "原因1",
        "原因2",
         ...
      ]
    },
    {
      "operateDay": "2021-03-05",
      "pass": "true",
      "count": 909,
      "failureReason": []
    }
  ]
}

10.参考

  • 《MongoDB高手课》- 唐建法
  • Spring 官网
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值