MongoDB:计算日期字段差值及工作日间隔的实现问题
错误原因及解决方案
1. 解决unknown operator: $cal_date1报错
MongoDB的聚合管道中,同一个阶段内无法引用该阶段刚生成的计算字段。你在同一个$project里同时定义cal_date1和引用$cal_date1计算日期差,自然会识别失败。你需要把日期差的计算逻辑拆分到下一个独立的聚合阶段,比如新增一个$addFields或者$project阶段。
2. 解决unknown operator: $dateDiff报错
$dateDiff是MongoDB 5.0及以上版本才支持的运算符,如果你使用的是更低版本的MongoDB,需要用兼容旧版本的计算方式:将日期转为时间戳相减后除以一天的毫秒数(86400000)取整,就能得到两个日期的间隔天数。
3. 完整可运行的聚合代码示例
db.collection.aggregate([ // 第一阶段:计算cal_date1、cal_date2、cal_date3 { $project: { "uniqueid": 1, "date1": 1, "date2": 1, "date3": 1, "date4": 1, "date5": 1, "cal_date1": { $switch: { branches: [ { case: {$ne:["$date2",null]}, then: "$date2"}, { case: {$ne:["$date3",null]}, then: "$date3"}, { case: {$ne:["$date4",null]}, then: "$date4"}, { case: {$ne:["$date5",null]}, then: "$date5"} ], default: "blank" } }, "cal_date2": { $switch: { branches: [ { case: {$ne:["$date4",null]}, then: "$date4"}, { case: {$ne:["$date5",null]}, then: "$date5"} ], default: "blank" } }, "cal_date3": { $switch: { branches: [ { case: {$ne:["$date5",null]}, then: "$date5"} ], default: "blank" } } } }, // 第二阶段:计算日期差值,解决同阶段引用问题 { $addFields: { "cal_days_between_date1_caldate1": { $switch: { branches: [ {case: { $eq: ["$date1", null]}, then: "blank"}, {case: { $eq: ["$cal_date1", "blank"]}, then: "blank"} ], // 兼容低版本MongoDB的日期差计算,如果你用5.0+可以替换回$dateDiff default: { $floor: { $divide: [ { $subtract: [ { $dateFromString: { dateString: "$cal_date1" } }, { $dateFromString: { dateString: "$date1" } } ]}, 86400000 // 一天的毫秒数 ] } } } } } } ])
扩展问题:计算两个日期之间的工作日天数
你可以用$range生成两个日期之间的所有日期列表,再过滤掉周六和周日后统计数量即可,示例计算逻辑如下(你可以把它加到上面的第二阶段中):
"work_days_between": { $cond: { if: { $or: [ { $eq: ["$date1", null] }, { $eq: ["$cal_date1", "blank"] } ] }, then: "blank", else: { $size: { $filter: { input: { $range: [ 0, { $ceil: { $divide: [ { $subtract: [ { $dateFromString: { dateString: "$cal_date1" } }, { $dateFromString: { dateString: "$date1" } } ] }, 86400000 ] }} ] }, as: "dayOffset", cond: { $not: { $in: [ { $dayOfWeek: { $add: [ { $dateFromString: { dateString: "$date1" } }, { $multiply: ["$$dayOffset", 86400000] } ] } }, [1, 7] // 1是周日,7是周六,直接过滤 ] } } } } } } }
内容的提问来源于stack exchange,提问作者Curious
相关产品推荐
相关产品推荐

