代码编织梦想

     简明:本文详细记录使用Aggregation聚合框架对MongoDB数据库常见操作,包括过滤、分组、求和、排序和分页设计实现等等。相比较于MongoTemplate,使用Aggregation对MongoDB操作更加便捷、方便,特别是分组求和、计算平均值情况等。
        (文章持续更新------后期添加更多基本操作)

        (个人记录学习总结内容,若出现错误/改进地方,请指出/分享,共同学习进步!!!)

一、简介
1、聚合简介

          MongoDB中聚合通常用来处理数据,如分组求和、求平均值和排序等,对实现数据复杂操作较为方便,简单来说:聚合就是通过对集合中的数据进行运算,转换为自己需要的形式。
         与上篇文章使用MongoTemplate操作数据相比较,Aggregation聚合操作显得更加有优势和便捷,代码清晰简洁,优化查询语句。
2、聚合管道简介

         简明:在Linux中,管道一般是将当前命令的执行结果作为下个命令执行的参数。

         MongoDB聚合管道:将MongoDB文档在一个管道处理完毕后,将结果传递给下一个管道处理。简单来说:管道就是聚合的整个运算过程。
3、聚合管道常用的表达式(常用)
表达式    功能    等价SQL
$match    过滤数据,输出符合条件文档    where
$project    修改输入文档结构(筛选展示文档的键)    个人理解(select)
$limit    限制计算文档结果返回数    limit
$sort    文档排序    order by
$group    文档分组    group by
$skip    跳过指定数量的文档    skip
$unwind    展开数组(数组内容拆分显示)    无
二、测试案例

测试数据如下:

 1、实体类

                 简明:为简化代码,已引入Lombok依赖,省略Setter()、Getter()方法

                 简明:@Document注解指定数据存储/操作的集合是PersonCollection

    import lombok.Getter;
    import lombok.Setter;
    import org.bson.types.ObjectId;
    import org.springframework.data.annotation.Id;
    import org.springframework.data.mongodb.core.mapping.Document;
     
    /**
     *  Person 实体类
     *
     *  @Document注解  默认情况下,创建Person集合(可使用@Document注解指定创建集合PersonCollection)
     *
     *  @author LBF
     *  @date 2022/1/18 11:18
     */
    @Setter
    @Getter
    @Document(collection = "PersonCollection")
    public class Person {
     
        /** Id */
        @Id
        private ObjectId id;
     
        /** 名字 */
        private String name;
     
        /** 年龄 */
        private Integer age;
     
        /** 地址 */
        private String addr;
     
        /** 手机号 */
        private Integer phone;
     
        /** 类别(测试用) */
        private String type;
     
        public Person(String name, Integer age, String addr, Integer phone, String type) {
            this.name = name;
            this.age = age;
            this.addr = addr;
            this.phone = phone;
            this.type = type;
        }
     
        @Override
        public String toString() {
            return "Person{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    ", addr='" + addr + '\'' +
                    ", phone=" + phone +
                    ", type='" + type + '\'' +
                    '}';
        }
    }

2、测试代码

      注意:测试代码中,键值是指数据库文档的键,而不是指实体类的键值(没有使用反射机制)

(1)常见聚合查询------->match(过滤)、group by(分组)、sum(求和)、sort(排序)

        /**
         *   常见聚合查询 ---------- 1
         *   @return  个人封装的返回体
         */
        @GetMapping("/findDocumentByAgg1")
        public AjaxResult findDocumentByAgg1(){
            //  初始化查询容器(用来构建查询条件)
            Criteria criteria = new Criteria();
            //  设置查询条件:  23  <=  age   <=  30
            criteria.and("age").gte(23).lte(30);
     
            //  构建聚合操作
            Aggregation aggregation = Aggregation.newAggregation(
                    //   使用反射机制,此时的键就是指实体类
                    //   Person.class,
     
                    //   利用构建的查询条件进行过滤数据
                    Aggregation.match(criteria),
                    //   根据 type 键分组  ------>   求和 age 键  -------->  每个分组的求和结果取个别名:totalAge
                    Aggregation.group("type").sum("age").as("totalAge"),
                    //   将分组求和的结果totalAge,按照降序排序
                    Aggregation.sort(Sort.by("totalAge").descending())
            );
     
            //  将拼接的聚合管道操作传入    
            //  第一个参数:aggregation聚合操作   
            //  第二个参数:操作的集合名称   
            //  第三个参数:输出类型(此处使用Document,包含_id键情况下使用实体类Person会类型转换报错)
            AggregationResults<Document> results =
                    mongoTemplate.aggregate(aggregation,"PersonCollection",Document.class);
            return AjaxResult.success(results.getMappedResults());
        }

(2)常见聚合查询------->project(展示键)、skip(跳过)

        @GetMapping("/findDocumentByAgg2")
        public AjaxResult findDocumentByAgg2(){
            //  初始化查询容器(用来构建查询条件)
            Criteria criteria = new Criteria();
            //  设置查询条件:  23  <=  age   <=  30
            criteria.and("age").gte(23).lte(30);
     
            Aggregation aggregation = Aggregation.newAggregation(
                    //  过滤数据
                    Aggregation.match(criteria),
                    //  选择结果需要展示的字段(默认是全展示,_id键会显示)
                    Aggregation.project("name","addr"),
                    //  跳过1个结果,显示剩余,即剩余1个结果
                    Aggregation.skip(1)
            );
     
            AggregationResults<Document> results = mongoTemplate.aggregate(aggregation,"PersonCollection",Document.class);
            return AjaxResult.success(results.getMappedResults());
        }

 (3)常见聚合查询------->(分页查询,以查询第2页为例)(首页第1页)

Aggregation聚合分页查询思路: skip跳过2个数据,limit每页显示最大文档数2个,跳过1、2个数据,即显示第3、4个数据,因此就显示第2页。

        /**  Aggregation 分页查询 */
        @GetMapping("/findDocumentByAgg3")
        public AjaxResult findDocumentByAgg3(){
     
            //  构建聚合操作
            Aggregation aggregation = Aggregation.newAggregation(
                    //  展示的键   name   phone  _id键会显示
                    Aggregation.project("name","phone"),
                    //  跳过某数量的数据,显示剩余(可理解为显示的第几页,如以下:跳过3个,显示第2页)
                    //  计算思路:skip((页码-1)* maxElements)
                    Aggregation.skip(1*2),
                    //  利用limit:限制输出的文档数,即需展示的数据量(可理解为每页显示的数量)
                    Aggregation.limit(2)
            );
            AggregationResults<Document> results = mongoTemplate.aggregate(aggregation,"PersonCollection",Document.class);
            return AjaxResult.success(results.getMappedResults());
        }

(4)常见聚合查询------->(持续补充)
 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_49745810/article/details/129629375