You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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完全支持上述用到的ConditionalOperatorsArithmeticOperators等操作符,对应MongoDB 3.2+版本,适配你的环境要求。

内容的提问来源于stack exchange,提问作者Paizo

火山引擎 最新活动