MongoTemplate官方文档:
一、增删改查
原生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 ; }}");
GroupByResults<DeviceGroupByResult> results =
//criteria: 筛选条件 , CTL_HEART_BEAT:集合名称/表名 ,DeviceGroupByResult.class:接收数据对象 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++; } |