MongoDB中无法对Timestamp执行$subtract运算的解决方案咨询
解决MongoDB Timestamp类型无法用$subtract计算差值的问题
这个问题我之前也帮人排查过,确实MongoDB的BSON Timestamp类型(和咱们常用的Date/ISODate不是一回事,它主要是MongoDB内部用来做oplog这类操作的)不支持直接用$subtract做减法运算,不过有两种简单的替代方案能解决:
方法1:转成64位整数后直接计算差值
用$toLong运算符把Timestamp转换成对应的64位整数值,之后就能正常做减法了。这个整数值里包含了时间部分(高32位是Unix时间秒数)和计数器部分(低32位),如果你的场景只需要知道两次记录的先后时间差,直接相减就能得到以Timestamp内部计数为单位的差值;要是需要转成秒或者毫秒,后续再加个$divide处理就行。
修改后的聚合查询如下:
{ "collection": "visits_logs", "aggregate": [ { "$group": { "_id": { "_sid": "$_sid" }, "first1": { "$first": "$_time" }, "last1": { "$last": "$_time" }, "HTTP_REFERER_HOST": { "$first": "$HTTP_REFERER_HOST" } } }, { "$project": { "length": { "$subtract": [ { "$toLong": "$last1" }, { "$toLong": "$first1" } ] }, "HTTP_REFERER_HOST": 1 } } ] }
方法2:提取纯粹的时间部分(秒级)计算差值
如果只关心时间本身的差值,想排除Timestamp里的计数器部分,可以通过位运算提取高32位的Unix时间秒数,再做减法。这样得到的就是纯粹的秒级时间差:
{ "collection": "visits_logs", "aggregate": [ { "$group": { "_id": { "_sid": "$_sid" }, "first1": { "$first": "$_time" }, "last1": { "$last": "$_time" }, "HTTP_REFERER_HOST": { "$first": "$HTTP_REFERER_HOST" } } }, { "$project": { "length": { "$subtract": [ { "$shiftRight": [ { "$toLong": "$last1" }, 32 ] }, { "$shiftRight": [ { "$toLong": "$first1" }, 32 ] } ] }, "HTTP_REFERER_HOST": 1 } } ] }
这里的$shiftRight是把64位整数右移32位,直接取出高32位的秒数,相减后就是两次记录的时间差秒数。
额外小提示
要是你的_time字段其实是Date/ISODate类型(很多人会把Timestamp和Date搞混),那直接用$subtract是完全支持的,得到的差值是毫秒数。如果确定是Timestamp类型,上面的两种方法就都能解决问题啦。
内容的提问来源于stack exchange,提问作者Abdol
相关产品推荐
相关产品推荐

