众妙之门

业精于勤,荒于嬉;行成于思,毁于随

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

MongoTemplate官方文档:

https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.aggregation.supported-aggregation-operations

一、增删改查

原生mongo:

Query对象

1、 创建一个query对象(用来封装所有条件对象),再创建一个criteria对象(用来构建条件)

2 、精准条件:criteria.and("key").is("条件") 模糊条件:criteria.and("key").regex("条件")

3、封装条件:query.addCriteria(criteria)

4、大于(创建新的criteria):Criteria gt = Criteria.where("key").gt("条件") 小于(创建新的criteria):Criteria lt = Criteria.where("key").lt("条件") 5、Query.addCriteria(new Criteria().andOperator(gt,lt));

6、一个query中只能有一个andOperator()。其参数也可以是Criteria数组。

7、排序 :query.with(new Sort(Sort.Direction.ASC, "age"). and(new Sort(Sort.Direction.DESC, "date")))

二、mongoTemplate分组排序、复杂操作

   

分组方法

理解难度

性能对比

是否提倡

mongoTemplate.group();

对比来将这个简单点

70w数据需要2分30秒

在springBoot新的集成环境下,mongoDB已经淘汰该方法了

mongoTemplate.aggregation();

理解之后特别好用

同环境下只需10秒不到

使用中

   1、mongoTemplate.group(); 分组但并不能使用排序,已经废弃

        //封装具体的筛选条件
        Criteria criteria = new Criteria();
        criteria.andOperator(
                // 筛选大于 getMsgTime > startTime 和 getMsgTime < endTime 的数据 (getMsgTime)
                Criteria.where("getMsgTime").gte(startTime),
                Criteria.where("getMsgTime").lte(endTime));
        //mongoDB按"deviceCode"分组 ,这里会默认保留分组字段
        GroupBy groupBy = GroupBy.key("deviceCode")
                //新增保留字段 并初始化
                .initialDocument("{ count: 0 , onlineCount: 0 , lastTime: 0}")
                //对分组后的数据进行运算 doc代表当前文档,prev代表结果文档 func里面可以使用js语法
                .reduceFunction("function(doc, prev) { prev.count++ ; if(doc.ctlStatus == 1){prev.onlineCount += 1 ;prev.lastTime = doc.getMsgTime ; }}");
        //criteria: 筛选条件 , CTL_HEART_BEAT:集合名称/表名 ,DeviceGroupByResult.class:接收数据对象
        GroupByResults<DeviceGroupByResult> results = mongoTemplate.group(criteria, "CTL_HEART_BEAT", groupBy, DeviceGroupByResult.class);

        /**这里的接收数据 对象 指的是 将 保留字段 封装成一个对象,并添加get/set方法
         * 这里 DeviceGroupByResult.class 类中就包含 deviceCode、count、onlineCount、lastTime 这些属性。
         */
        //对结果集进行处理 这里只能拿到iterator对象,在我看来itertator并没有List集合 香
        Iterator<DeviceGroupByResult> iterator = results.iterator();
        while (iterator.hasNext()) {
            //看了下源码这个地方 result.iterator 返回的就是就是结果集 但是只能用迭代器读取
            DeviceGroupByResult deviceGroupByResult = iterator.next();
        }

2、mongoTemplate.aggregation(); 分组并排序,推荐使用这种方式

        //封装具体的筛选条件
        Criteria criteria = new Criteria();
        criteria.andOperator(
                // 筛选大于 getMsgTime > startTime 和 getMsgTime < endTime 的数据 (getMsgTime)
                Criteria.where("getMsgTime").gte(startTime),
                Criteria.where("getMsgTime").lte(endTime));
        //mogoDB按device_code分组查询
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),//添加筛选方法
                Aggregation.group("deviceCode").first("deviceCode").as("deviceCode") //利用deviceCode分组并保留该字段
                        .last("getMsgTime").as("lastTime")//取最后时间作为保留
                        .count().as("count")//统计分个数
                        //这里的ctlStatus在mongoDB里面是以字符串存储,而我想统计它们之和,但是字符串不能直接相加sum(),所以只能先存到List中
                        .push("ctlStatus").as("currentCtlStatusList")
                        .push("getMsgTime").as("cuurentCtlGetTimeList")//这里之所以把时间也push上去,是因为我要取ctlstatus=1时候的时间
                //这里排序放在分组后面,所以指定的字段只能是lastTime,而放在分组前面就需要指定getMsgTime数据库字段
                //而且使用sort要注意,sort我发现在70w数据面前 就歇菜了 ,而且回报错
                Aggregation.sort(Sort.by(Sort.Order.asc("lastTime")))
        );

        //aggegation:所有条件的封装 , CTL_HEART_BEAT:集合/表 ,DeviceGroupByResult.class:接收数据对象
        AggregationResults<DeviceGroupByResult> deviceGroupByResults = mongoTemplate.aggregate(aggregation, "CTL_HEART_BEAT", DeviceGroupByResult.class);
        //这里就很友好了
        List<DeviceGroupByResult> list = deviceGroupByResults.getMappedResults();

3、循环查询(可能你会遇见需要你循环几次的操作)

        Criteria criteria = new Criteria();
        //timeFrames  时间集合
        for (String time : timeFrames) {
            //将筛选条件封装到agregaton
            Aggregation aggregation = Aggregation.newAggregation(
                    //注意这里使用的是 new criteria.adddOperator(criteria) 每次循环都带一个全新的Criteria条件
                    //按照正常逻辑 是不需要在外面 包一层,但是如你这样做了
                    //循环第一遍没问题,第二遍嘿嘿  会提示  对一个参数做了多次筛选,所以这里做了一个隐式传参
                    Aggregation.match(new Criteria().andOperator(criteria.where("STATISTICS_YEAR").is(time), criteria)),
                    Aggregation.group("STATISTICS_TIME").first("STATISTICS_TIME").as("time").sum("CAR_FLOW").as("count"),
                    Aggregation.sort(Sort.by(Sort.Order.asc("time")))
            );
            AggregationResults<CarFlowResultVO> carFlowResultVOs = mongoTemplate.aggregate(aggregation, tableName, CarFlowResultVO.class);
            carFlowResultVOList = carFlowResultVOs.getMappedResults();
            carFlowResultVOMap.put(String.valueOf(count), carFlowResultVOList);
            carFlowResultVOList = new ArrayList<>();
            count++;
        }

 转载:https://www.cnblogs.com/tiankx/p/13957842.html

posted on 2023-01-05 10:41  xuanm  阅读(603)  评论(0编辑  收藏  举报