MongoDB中如何按相同ID且日期差为1天的条件分组数据?
MongoDB实现相同ID下连续日期(差值1天)的分组方案
针对相同ID且日期差值为1天的记录分组需求,普通group by无法直接实现,需要借助MongoDB的聚合管道+窗口函数来完成,具体方案如下:
假设数据结构
假设你的集合名为records,文档结构如下(若Date字段已是MongoDB原生Date类型,可跳过后续的日期转换步骤):
{ "ID": 1, "Date": "3.13.2023", "num": 1 } { "ID": 1, "Date": "3.12.2023", "num": 2 } { "ID": 1, "Date": "2.14.2023", "num": 3 }
完整聚合管道代码
db.records.aggregate([ // 1. 将字符串日期转换为MongoDB Date类型(Date字段已是Date类型则跳过) { $addFields: { convertedDate: { $dateFromString: { dateString: "$Date", format: "%m.%d.%Y" // 匹配日期字符串格式:月.日.年 } } } }, // 2. 按ID和日期升序排序,确保同ID记录按日期顺序排列 { $sort: { ID: 1, convertedDate: 1 } }, // 3. 用窗口函数计算相邻日期差,生成分组标识 { $setWindowFields: { partitionBy: "$ID", // 按ID分区处理 sortBy: { convertedDate: 1 }, // 分区内按日期排序 output: { // 计算当前记录与前一条的日期差(天数) prevDateDiff: { $dateDiff: { startDate: { $lag: "$convertedDate" }, endDate: "$convertedDate", unit: "day" } }, // 生成分组ID:非连续日期时累加1,连续日期时累加0 group_id: { $sum: { $cond: [ { $or: [{ $eq: ["$prevDateDiff", null] }, { $ne: ["$prevDateDiff", 1] }] }, 1, 0 ] }, window: { documents: ["unbounded", "current"] } } } } }, // 4. 按ID和分组标识聚合记录 { $group: { _id: { ID: "$ID", group_id: "$group_id" }, groupedRecords: { $push: { Date: "$Date", num: "$num" } } } }, // 5. 调整输出格式(可选) { $project: { _id: 0, ID: "$_id.ID", groupedRecords: 1 } } ])
步骤说明
- 日期转换:将字符串格式的日期转为MongoDB原生
Date类型,确保能使用$dateDiff计算日期差。 - 排序:按ID和日期升序排序,保证同ID的记录按时间顺序排列,为后续窗口函数计算相邻日期差做准备。
- 窗口函数计算分组标识:
$lag获取分区内前一条记录的日期,$dateDiff计算当前日期与前一条的天数差;- 通过累加规则生成
group_id:第一条记录或日期差不为1天时,group_id累加1,否则累加0,确保连续日期的记录拥有相同group_id。
- 分组聚合:按
ID和group_id分组,用$push将同组记录聚合为数组。 - 格式调整:可选步骤,简化输出结构,让结果更直观。
预期输出
运行上述管道后,会得到符合需求的分组结果:
[ { "ID": 1, "groupedRecords": [ { "Date": "2.14.2023", "num": 3 } ] }, { "ID": 1, "groupedRecords": [ { "Date": "3.12.2023", "num": 2 }, { "Date": "3.13.2023", "num": 1 } ] } ]
内容的提问来源于stack exchange,提问作者HilaLewin
相关产品推荐
相关产品推荐

