Spring Data MongoDB聚合框架:用project()中ConditionalOperators计算中位数
在Spring Data 2.0中计算温度中位数的实现方案
针对你在基于Spring Data 2.0的项目中,需要计算MongoDB里冰箱温度文档中位数的需求,我整理了一套完整的实现逻辑,结合MongoDB聚合管道和Spring Data的API来完成,步骤如下:
1. 核心思路梳理
计算中位数的关键逻辑是:
- 筛选目标文档(比如按设备ID、时间范围)
- 按温度值排序,确保数据有序
- 收集所有温度值到数组并统计文档总数
- 根据总数的奇偶性计算中位数:奇数取中间位置的数值,偶数取中间两个数值的平均值
2. 完整代码实现
首先,定义一个用于接收聚合结果的实体类:
public class MedianTemperatureResult { private long total; // 匹配到的文档总数 private List<Integer> temps; // 排序后的温度数组 private Double medianTemperature; // 最终计算出的中位数 // 生成getter和setter方法 }
接下来编写聚合操作的业务代码:
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.aggregation.*; import org.springframework.data.domain.Sort; import java.util.Date; // 假设已通过Spring注入MongoTemplate @Autowired private MongoTemplate mongoTemplate; public Double calculateTemperatureMedian(String deviceId, Date startTime, Date endTime) { // 1. 匹配条件:筛选指定设备、时间范围内的文档 MatchOperation matchOp = Aggregation.match( Criteria.where("deviceId").is(deviceId) .and("time").gte(startTime).lte(endTime) ); // 2. 按温度升序排序,保证数组内的温度是有序的 SortOperation sortOp = Aggregation.sort(Sort.Direction.ASC, "temperature"); // 3. 分组操作:收集所有温度到数组,并统计文档总数 GroupOperation groupOp = Aggregation.group() .push("temperature").as("temps") .count().as("total"); // 4. 投影操作:根据总数奇偶性计算中位数 ProjectOperation projectOp = Aggregation.project("total", "temps") .and(ConditionalOperators.when(Criteria.where("total").mod(2).is(1)) // 奇数情况:取数组中间位置的元素,索引为 (total-1)/2 .then(ArrayOperators.ArrayElemAt.arrayOf("temps") .elementAt(ArithmeticOperators.Floor.floor( ArithmeticOperators.Subtract.valueOf("total").subtract(1) .divideBy(2) )) ) // 偶数情况:取中间两个元素的平均值 .otherwise(ArithmeticOperators.Avg.avgValues( ArrayOperators.ArrayElemAt.arrayOf("temps") .elementAt(ArithmeticOperators.Divide.valueOf("total").divideBy(2)), ArrayOperators.ArrayElemAt.arrayOf("temps") .elementAt(ArithmeticOperators.Subtract.valueOf( ArithmeticOperators.Divide.valueOf("total").divideBy(2) ).subtract(1)) )).as("medianTemperature"); // 组装完整的聚合管道 Aggregation aggregation = Aggregation.newAggregation(matchOp, sortOp, groupOp, projectOp); // 执行聚合查询,关联到对应的MongoDB集合 AggregationResults<MedianTemperatureResult> results = mongoTemplate.aggregate( aggregation, "refrigerator", // 替换为你的MongoDB集合名称 MedianTemperatureResult.class ); // 处理空结果场景,返回中位数或null MedianTemperatureResult result = results.getUniqueMappedResult(); return result != null ? result.getMedianTemperature() : null; }
3. 关键细节说明
- 数据类型适配:如果你的
temperature字段是整数类型,偶数场景下计算出的中位数会是小数,用Double类型接收结果更合理。 - 空值处理:如果没有匹配到任何文档,
result会为null,可以根据业务需求返回默认值或抛出提示。 - 版本兼容性:Spring Data 2.0完全支持上述用到的
ConditionalOperators、ArithmeticOperators等操作符,对应MongoDB 3.2+版本,适配你的环境要求。
内容的提问来源于stack exchange,提问作者Paizo




