【MongoDB】--MongoDB聚合Aggregation

目录

一、前言

聚合操作组值来自多个文档,可以对分组数据执行各种操作以返回单个结果。聚合操作包含三类:单一作用聚合、聚合管道、MapReduce

  • 单一作用聚合:提供对常见聚合过程的简单访问,操作都从单个集合聚合文档
  • 聚合管道操作:将文档在一个管道处理完毕后,把处理的结果传递给下一个管道进行再次处理
  • MapReduce操作:是将集合中的批量文档进行分解处理,然后将处理后的各个结果进行合并输出

二、聚合管道操作

管道的主要函数方法如下:

java 复制代码
名称	                描述	                  类比sql
$avg	      计算均值	   avg
$first	  返回每组第一个文档,如果有排序,按照排序,如果没有按照默认的存储的顺序返回第一个文档。 	  limit 0,1
$last	返回每组最后一个文档,如果有排序,按照排序,如果没有按照默认的存储的顺序返回最后一个文档。	 -
$max	根据分组,获取集合中所有文档对应值的最大值。	 max
$min	根据分组,获取集合中所有文档对应值的最小值。	 min
$push	将指定的表达式的值添加到一个数组中。	 -
$addToSet	将表达式的值添加到一个集合中(无重复值,无序)。	-
$sum	计算总和	 sum
$stdDevPop	返回输入值的总体标准偏差(population standard deviation)	-
$stdDevSamp	返回输入值的样本标准偏差(the sample standard deviation)	-

2.1、实际案例1

classDo是班级信息

StudentDo是学生信息

teacherDo是老师信息

 一个学生 关联一个班级;一个班级有多个学生;
 一个老师挂在多个班级下;一个班级拥有多个老师;

主要表结构字段:

java 复制代码
ClassDo班级信息
   @JSONField(name = "class_no")
    private String classNo;
    @JSONField(name = "class_name")
    private String className;
    @JSONField(name = "class_position")
    private String classPosition;
 
    List<StudentDo> studentDos; //关联学生们
    List<TeacherDo> teacherDos; //关联老师们

StudentDo学生信息
   @JSONField(name = "stu_id")
    private String stuId;
    @JSONField(name = "stu_name")
    private String stuName;
    @JSONField(name = "stu_age")
    private String stuAge;
    @JSONField(name = "chinese_score")
    private String chineseScore;
    @JSONField(name = "match_score")
    private String matchScore;
    @JSONField(name = "class_id")
    private ObjectId classId; //学生属于哪个班级
    
    ClassDo classDo; //学生属于具体哪个班

TeacherDo老师信息
    @JSONField(name = "te_id")
    private String teId;
    @JSONField(name = "te_name")
    private String teName;
    @JSONField(name = "te_age")
    private String teAge;
    @JSONField(name = "class_ids")
    private List<ObjectId> classIds; //老师教学多个班级
   

(1)、案例--根据学生no,找到对应班级名称

java 复制代码
    public void aggregateStudent(String stuName,String stuAge){
        int page =2,maxElements=10;
        Criteria criteria = new Criteria();
        criteria.and("stuName").is(stuName);
        criteria.and("stuAge").is(stuAge);
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.lookup("w_class","classId","_id","classDo"),
//                Aggregation.unwind("classDo") //加上这行,那么classDo关联时,classDo节点为null,那么就去去掉这一行
                Aggregation.unwind("classDo",true), //classDo为null,这个数组[index]还存在,但classDo字段不存在了
                //  计算思路:skip((页码-1)* maxElements)
                Aggregation.sort(Sort.by("stu_age").descending()),
                Aggregation.skip((page-1)*maxElements),
                //  利用limit:限制输出的文档数,即需展示的数据量(可理解为每页显示的数量)
                Aggregation.limit(maxElements)
        );
        /**
         * aggregate()表明 主要查询w_student表,对应的查询条件是match(criteria);
         * 接着要关联w_class表。  w_student表的class_id字段关联w_class表的_id字段。
         */
        AggregationResults<JSONObject> aggregationResults = mongoTemplate.aggregate(aggregation, "w_student", JSONObject.class);
        List<JSONObject> infoList = aggregationResults.getMappedResults();
        log.info("aggregationResults:{}", JSON.toJSONString(infoList));

    }

(2)、案例--这个班级有哪些学生和哪些老师在任课

备注:主表有查询条件;关联两个子表;以主表返回结果

java 复制代码
  public void aggregateClass(String className){
        Criteria criteria = new Criteria();
        criteria.and("className").is(className);
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.lookup("w_student","_id","classId","studentDos"),
                Aggregation.lookup("w_teacher","_id","classIds","teacherDos")
        );
        AggregationResults<JSONObject> aggregationResults = mongoTemplate.aggregate(aggregation, "w_class", JSONObject.class);
        List<JSONObject> infoList = aggregationResults.getMappedResults();
        log.info("aggregationResults:{}", JSON.toJSONString(infoList));

    }

2.2、实际案例2

现有两个mongodb表,business_permission存储某个业务的权限信息;business_a表是具体某个业务;其中business_a表的主键id关联到business_permission表的business_id。

(1)、案例--主表和关联表都有条件限制,且分页返回

由于这里的查询要求分页,那么只能对要分页的主表进行返回。

java 复制代码
  public Object templateAggregation2(int page,int size){
         //主表的查询条件
        Criteria criteria = new Criteria();
        criteria.and("state").is(Boolean.TRUE);
        //关联表的查询条件
        Criteria permissionCri = new Criteria();
        permissionCri.and("templateInfo.business_type").is(7); 

        //
        /**
        templateInfo是关联的表结构;这个结构的permission节点是一个数组,在具体按照要求进行过滤得到需要的权限是否存在
        */
        Criteria businessCriteria = new Criteria();  businessCriteria.andOperator(Criteria.where("templateInfo.permission.id").is("04"),Criteria.where("templateInfo.permission.permission_type").is(2));
        Criteria businessCriteria2 = new Criteria();
businessCriteria2.andOperator(Criteria.where("templateInfo.permission.id").is("01"),Criteria.where("templateInfo.permission.permission_type").is(2));
        List<Criteria> busCriteriaList = new ArrayList<>();
        busCriteriaList.add(businessCriteria);
        busCriteriaList.add(businessCriteria2);
        busCriteriaList.add(Criteria.where("templateInfo.all_flag").is(Boolean.TRUE));
        busCriteriaList.add(Criteria.where("templateInfo.permission").is(null));
        busCriteriaList.add(Criteria.where("templateInfo.permission").is(new ArrayList<>()));
        Criteria[] criArray = new Criteria[busCriteriaList.size()];
        busCriteriaList.toArray(criArray);
        permissionCri.orOperator(criArray);

        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria), //主mongodb自身查询条件
                Aggregation.lookup("business_permission","_id","business_id","templateInfo"), //business_permission的business_id对应主表的id
                Aggregation.match(permissionCri), //关联表查询条件
                Aggregation.sort(new Sort(Sort.Direction.DESC, "update_time")),
                 //  计算思路:skip((页码-1)* maxElements)
                 Aggregation.skip((page-1)*size),
                 Aggregation.limit(size)  //这分页的
              //  Aggregation.group("template_type") //按照分组返回特定的字段值 【可以统计数量】
             //   .sum("id").as("sumValue")  //对id进行求和 
             //   .first("template_code").as("templateCode")
             //   .avg("doc_view_number").as("avgValue")
        );

        AggregationResults<JSONObject> aggregationResults = mongoTemplate.aggregate(aggregation, "business_a", JSONObject.class);
        List<JSONObject> templateList = aggregationResults.getMappedResults();
        log.info("templateList All:{}", JSON.toJSONString(templateList));
        return templateList;
    }
相关推荐
你的微笑,乱了夏天1 天前
linux centos 7 安装 mongodb7
数据库·mongodb
来一杯龙舌兰1 天前
【MongoDB】使用 MongoDB 存储日志、审批、MQ等数据的案例及优点
数据库·mongodb
技术路上的苦行僧1 天前
分布式专题(8)之MongoDB存储原理&多文档事务详解
数据库·分布式·mongodb
Tttian6222 天前
Pycharm访问MongoDB数据库
数据库·mongodb·pycharm
Benjamin Cheung2 天前
starter-data-mongodb
数据库·mongodb
2301_801483692 天前
MongoDB(下)
数据库·mongodb
s_fox_3 天前
Mongodb 集群搭建
数据库·mongodb
赶紧写完去睡觉3 天前
数据库管理系统——NoSQL之文档数据库(MongoDB)
数据库·mongodb·nosql
ziyu_jia4 天前
MongoDB、Mongoose使用教程
前端·数据库·mongodb·node.js·mongoose
颜淡慕潇4 天前
【数据库系列】Spring Boot 集成 MongoDB Template 的详细步骤
数据库·spring boot·后端·mongodb