MongoDB聚合:如何基于字段值条件转换时长字符串为小时数?
MongoDB聚合:条件转换时长字符串为小时数
场景与需求
现有MongoDB文档包含_id和value字段,value值可为字符串或整数,示例文档:
{_id: 1, value: '13 hr 30mins'}, {_id: 2, value: '25 hr'}, {_id: 3, value: '45mins'}, {_id: 4, value: '8hr 15 mins'}, // 额外示例:非时长字符串或整数直接保留 {_id: 5, value: 'abc'}, {_id: 6, value: 100}
需求:
- 若
value是包含hr或mins的字符串,将其转换为小时数(如13 hr 30mins转为13.5) - 不满足条件的文档直接保留原字段值,最终输出示例:
{_id: 1, value: 13.5}, {_id: 2, value: 25}, {_id: 3, value: 0.75}, {_id: 4, value: 8.25}, {_id: 5, value: 'abc'}, {_id: 6, value: 100}
问题分析
你尝试的聚合代码存在逻辑错误:$match阶段不能嵌套$set或$cond来修改字段,且正则匹配的写法不正确,需要用$regexMatch判断字符串是否包含指定关键词,同时通过$cond在$set阶段实现条件转换。
正确聚合管道方案
使用以下聚合管道可以实现需求:
[ { $set: { value: { $cond: [ // 判断是否为包含hr或mins的字符串 { $and: [ { $eq: [{ $type: "$value" }, "string"] }, { $regexMatch: { input: "$value", regex: /hr|mins/i } } ] }, // 满足条件:转换为小时数 { $round: [ { $sum: [ // 提取小时数,无则为0 { $toInt: { $ifNull: [ { $regexFind: { input: "$value", regex: /(\d+)\s*hr/i } }.match[1], 0 ] } }, // 提取分钟数并转为小时,无则为0 { $divide: [ { $toInt: { $ifNull: [ { $regexFind: { input: "$value", regex: /(\d+)\s*mins?/i } }.match[1], 0 ] } }, 60 ] } ] }, 2 // 保留两位小数 ] }, // 不满足条件:保留原value "$value" ] } } } ]
代码说明
- 条件判断:通过
$and组合两个核心条件:value是字符串类型、包含hr或mins关键词 - 小时数提取:用
$regexFind匹配小时数,无匹配时返回0 - 分钟数转换:匹配分钟数后除以60转为小时单位,无匹配时返回0
- 结果合并:将小时数和转换后的分钟数相加,用
$round保留两位小数 - 默认处理:不满足转换条件时,直接返回原
value值
内容的提问来源于stack exchange,提问作者vadapav
相关产品推荐
相关产品推荐

