在聚合期间以几秒为单位获取MongoDB ISODate的unix时间戳

va5*_*5ja 4 mongodb unix-timestamp isodate mongodb-query aggregation-framework

我正在寻找这个,但我找不到任何有用的解决我的情况.我想要的是在聚合期间以几秒为单位获取MongoDB ISODate的unix时间戳.问题是我可以从ISODate中获取时间戳,但它是以毫秒为单位.所以我需要减少那些毫秒.我试过的是:

> db.data.aggregate([
    {$match: {dt:2}}, 
    {$project: {timestamp: {$concat: [{$substr: ["$md", 0, -1]}, '01', {$substr: ["$id", 0, -1]}]}}}
  ])
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我正在尝试从'md'var中获取时间戳,并将此时间戳与'01'和'id'数字连接起来.上面的代码给出:

{
    "_id" : ObjectId("52f8fc693890fc270d8b456b"),
    "timestamp" : "2014-02-10T16:20:56011141"
}
Run Code Online (Sandbox Code Playgroud)

然后我改进了命令:

> db.data.aggregate([
    {$match: {dt:2}},
    {$project: {timestamp: {$concat: [{$substr: [{$subtract: ["$md", new Date('1970-01-01')]}, 0, -1]}, '01', {$substr: ["$id", 0, -1]}]}}}
  ])
Run Code Online (Sandbox Code Playgroud)

现在我得到:

{
    "_id" : ObjectId("52f8fc693890fc270d8b456b"),
    "timestamp" : "1392049256000011141"
}
Run Code Online (Sandbox Code Playgroud)

我真正需要的是1392049256011141所以没有3额外的000.我尝试了$减法:

> db.data.aggregate([
    {$match: {dt:2}}, 
    {$project: {timestamp: {$concat: [{$substr: [{$divide: [{$subtract: ["$md", new Date('1970-01-01')]}, 1000]}, 0, -1]}, '01', {$substr: ["$id", 0, -1]}]}}}
  ])
Run Code Online (Sandbox Code Playgroud)

我得到的是:

{
    "_id" : ObjectId("52f8fc693890fc270d8b456b"),
    "timestamp" : "1.39205e+009011141"
}
Run Code Online (Sandbox Code Playgroud)

不完全是我对命令的期望.不幸的是,$ substr运算符不允许负长度.有没有人有其他解决方案?

Nei*_*unn 7

我不确定为什么你认为你需要以秒为单位而不是毫秒的值,因为通常两种形式都是有效的,并且在大多数语言实现中,毫秒实际上是首选的.但一般来说,尝试将其强制转换为字符串是错误的解决方法,通常你只是做数学:

db.data.aggregate([
  { "$project": {
    "timestamp": {
      "$subtract": [
        { "$divide": [
            { "$subtract": [ "$md", new Date("1970-01-01") ] },
            1000
        ]},
        { "$mod": [
          { "$divide": [
              { "$subtract": [ "$md", new Date("1970-01-01") ] },
              1000
          ]},
          1
        ]}
      ]
    }
  }}
])
Run Code Online (Sandbox Code Playgroud)

这会以秒为单位返回一个纪元时间戳.基本上从一个BSON日期对象从另一个BSON日期对象中减去时得出,结果是以毫秒为单位的时间间隔.使用"1970-01-01"的初始纪元日期导致基本上从当前日期值中提取毫秒值.的$divide操作者基本上起飞的毫秒部分和$mod确实模来实现舍入.

实际上,您最好使用母语为您的应用程序进行工作,因为所有BSON日期都将作为本机"日期/日期时间"类型返回,您可以在其中提取时间戳值.考虑shell中的JavaScript基础知识:

var date = new Date()
( date.valueOf() / 1000 ) - ( ( date.valueOf() / 1000 ) % 1 )
Run Code Online (Sandbox Code Playgroud)

通常使用聚合,您希望对时间戳值执行此类"数学运算",以便在诸如一天等时间段内聚合值.聚合框架可以使用日期运算符,但您也可以使用日期数学方式:

db.data.aggregate([
    { "$group": {
        "_id": {
          "$subtract": [
              { "$subtract": [ "$md", new Date("1970-01-01") ] },
              { "$mod": [
                  { "$subtract": [ "$md", new Date("1970-01-01") ] },
                  1000 * 60 * 60 * 24
              ]}
          ]
        },
        "count": { "$sum": 1 }
    }}
])
Run Code Online (Sandbox Code Playgroud)

这种形式更典型的是将时间戳舍入到一天,并在这些间隔内汇总结果.

因此,仅仅提取时间戳的聚合框架的目的似乎并不是最佳用法,或者实际上不需要将其转换为秒而不是毫秒.在您的应用程序代码中我认为您应该这样做,除非您当然希望结果的时间间隔可以应用所示的日期数学.

方法在那里,但除非你实际上是聚合,否则这将是你的应用程序的最差性能选项.代替转换代码.