【MongoDB】--MongoDB聚合Aggregation

一、前言

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

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

二、聚合管道操作

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

名称	                描述	                  类比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是老师信息

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

主要表结构字段:

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,找到对应班级名称

    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)、案例–这个班级有哪些学生和哪些老师在任课

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

  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)、案例–主表和关联表都有条件限制,且分页返回

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

  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.project().andInclude("_id","knowledge_source","knowledge_name","create_time","update_time"), //只返回这些字段
                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;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DreamBoy_W.W.Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值