求Mongo聚合查询对应Java代码:车辆每日行驶距离去重求和
解决Mongo聚合查询转Java代码的问题
原生Mongo查询逻辑梳理
你的原生查询核心是三个聚合阶段:
- $match:筛选指定
vehicleId、2022-08-24当天(时间范围>2022-08-24T00:00:00且<2022-08-25T00:00:00)、distanceMiles>0的记录 - $group:按
vehicleId+distanceMiles组合分组,过滤重复的距离记录 - $group:全局分组(
_id: null),对去重后的distanceMiles求和,得到总行驶距离
对应原生查询的完整Java代码
用Spring Data MongoDB的Aggregation API实现如下:
// 构造UTC时区的日期范围,匹配原生查询的时间条件 LocalDate targetDate = LocalDate.of(2022, 8, 24); Instant start = targetDate.atStartOfDay(ZoneOffset.UTC).toInstant(); Instant end = targetDate.plusDays(1).atStartOfDay(ZoneOffset.UTC).toInstant(); // 构建match条件 Criteria criteria = Criteria.where("vehicleId").is("ABCDEFGH") .and("timestamp").gt(start).lt(end) .and("distanceMiles").gt(0); // 组装聚合管道 Aggregation aggregation = Aggregation.newAggregation( // 阶段1:匹配过滤 Aggregation.match(criteria), // 阶段2:按vehicleId和distanceMiles分组去重 Aggregation.group("vehicleId", "distanceMiles"), // 阶段3:全局分组求和,引用上一阶段_id中的distanceMiles Aggregation.group() // 不传参数等价于原生的_id: null .sum("_id.distanceMiles").as("totalDistance") ); // 执行查询(需注入MongoTemplate实例) AggregationResults<DistanceSumResult> results = mongoTemplate.aggregate( aggregation, "collection1", DistanceSumResult.class ); // 结果接收实体类 class DistanceSumResult { private double totalDistance; // 生成getter、setter }
适配你现有代码补全最后分组
你的代码额外做了日期格式化、取最新timestamp的操作,若要保留这些逻辑并补全求和分组,调整如下:
Criteria criteria = new Criteria(); criteria.andOperator( Criteria.where("timestamp").gte(start).lte(end), Criteria.where("vehicleId").in(vehicleIdList) ); Aggregation aggregation = Aggregation.newAggregation( Aggregation.match(criteria), Aggregation.sort(Direction.DESC, "timestamp"), Aggregation.project("distanceMiles", "vehicleId", "timestamp") .and("timestamp").dateAsFormattedString("%Y-%m-%d").as("yearMonthDay"), // 你的现有分组逻辑:按车辆+日期分组,取最新记录并累计距离 Aggregation.group("vehicleId", "yearMonthDay") .first("vehicleId").as("vehicleId") .first("timestamp").as("lastReported") .sum("distanceMiles").as("distanceMiles"), // 补全全局分组:对所有车辆每日的距离求和 Aggregation.group() .sum("distanceMiles").as("totalDistance") );
关键注意点
- Spring Data MongoDB中,
Aggregation.group()不传参数时,默认对应原生的_id: null全局分组 - 引用上一阶段分组的复合
_id字段时,直接用"_id.字段名"作为聚合函数的参数,比如sum("_id.distanceMiles") - 日期处理需保持时区一致,原生查询用UTC,Java代码也要对应使用
ZoneOffset.UTC避免时间偏差
内容的提问来源于stack exchange,提问作者user1300830
相关产品推荐
相关产品推荐

