如何在MongoDB中对对象内部排序并计算对象内数值差值
MongoDB 数据处理需求实现方案
前置要求
本方案用到了MongoDB 5.2版本新增的$sortArray、$shift运算符,需确保你的MongoDB服务版本≥5.2,低版本可通过$unwind+$sort+$group的组合替换对应逻辑。
完整聚合查询代码
db.collection.aggregate([ // 拆解外层data的日期键为数组格式 { $project: { dateItems: { $objectToArray: "$data" } } }, // 展开日期数组,每个日期对应一条独立文档 { $unwind: "$dateItems" }, // 拆解每个日期下的小时键,拼接为完整ISO时间格式 { $project: { date: "$dateItems.k", hourItems: { $map: { input: { $objectToArray: "$dateItems.v" }, as: "hourItem", in: { time: { $concat: [ "$dateItems.k", "T", "$$hourItem.k", ":00:00:0Z" ] }, value: "$$hourItem.v" } } } } }, // 对单日内的所有时间点按时间升序排序 { $project: { date: 1, sortedHourItems: { $sortArray: { input: "$hourItems", sortBy: { time: 1 } } } } }, // 提取单日最早、最晚时间和对应值,统计当日数值数量 { $project: { date: 1, dayFirstTime: { $first: "$sortedHourItems.time" }, dayFirstValue: { $first: "$sortedHourItems.value" }, dayLastTime: { $last: "$sortedHourItems.time" }, dayLastValue: { $last: "$sortedHourItems.value" }, dayCount: { $size: "$sortedHourItems" } } }, // 窗口函数获取前一日的最晚时间和对应值,用于单日单值场景计算 { $setWindowFields: { sortBy: { date: 1 }, output: { prevDayLastValue: { $shift: { output: "$dayLastValue", by: -1, default: null } }, prevDayLastTime: { $shift: { output: "$dayLastTime", by: -1, default: null } } } } }, // 按规则计算差值,输出符合要求的文档结构 { $project: { _id: 0, data: { time_first: { $cond: { if: { $gt: [ "$dayCount", 1 ] }, then: "$dayFirstTime", else: "$prevDayLastTime" } }, value_first: { $cond: { if: { $gt: [ "$dayCount", 1 ] }, then: "$dayFirstValue", else: "$prevDayLastValue" } }, time_last: "$dayLastTime", value_last: "$dayLastValue", "difference_value_last-value_first": { $subtract: [ "$dayLastValue", { $cond: { if: { $gt: [ "$dayCount", 1 ] }, then: "$dayFirstValue", else: "$prevDayLastValue" } } ] } } } } ])
逻辑说明
- 首先通过
$objectToArray把嵌套的对象结构转为可遍历的数组,方便拼接完整时间字符串 - 用
$sortArray对单日内的时间点按时间排序,直接提取首尾值作为单日的first、last值 - 通过窗口函数
$setWindowFields的$shift操作取到前一日的last值,解决单日仅1个值的计算场景 - 最后用
$cond判断当日数值数量,按规则生成最终的first值和差值
内容的提问来源于stack exchange,提问作者bc110402922
相关产品推荐
相关产品推荐

