【问题标题】:Getting unix timestamp in seconds out of MongoDB ISODate during aggregation在聚合期间从 MongoDB ISODate 中以秒为单位获取 unix 时间戳
【发布时间】:2014-09-05 17:11:37
【问题描述】:

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

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

如您所见,我正在尝试从“md”var 中获取时间戳,并将此时间戳与“01”和“id”号连接起来。上面的代码给出:

{
    "_id" : ObjectId("52f8fc693890fc270d8b456b"),
    "timestamp" : "2014-02-10T16:20:56011141"
}

然后我改进了命令:

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

现在我明白了:

{
    "_id" : ObjectId("52f8fc693890fc270d8b456b"),
    "timestamp" : "1392049256000011141"
}

我真正需要的是 1392049256011141,所以没有 3 个额外的 000。我尝试使用 $subtract:

> 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]}]}}}
  ])

我得到的是:

{
    "_id" : ObjectId("52f8fc693890fc270d8b456b"),
    "timestamp" : "1.39205e+009011141"
}

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

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework unix-timestamp isodate


    【解决方案1】:

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

    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
            ]}
          ]
        }
      }}
    ])
    

    它会以秒为单位返回一个纪元时间戳。基本上是从另一个 BSON 日期对象减去一个 BSON 日期对象得出的,结果是以毫秒为单位的时间间隔。使用“1970-01-01”的初始纪元日期实际上会从当前日期值中提取毫秒值。 $divide 运算符实质上去掉了毫秒部分,$mod 进行取模以实现舍入。

    确实,尽管您最好使用本机语言为您的应用程序进行工作,因为所有 BSON 日期都将作为本机“日期/日期时间”类型返回,您可以在其中提取时间戳值。考虑一下 shell 中的 JavaScript 基础知识:

    var date = new Date()
    ( date.valueOf() / 1000 ) - ( ( date.valueOf() / 1000 ) % 1 )
    

    通常对于聚合,您希望对时间戳值执行这种“数学运算”,以用于在某个时间段(例如一天)内聚合值。聚合框架可以使用日期运算符,但您也可以使用日期数学方法:

    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 }
        }}
    ])
    

    这种形式更典型的是发出一个四舍五入的时间戳,并在这些时间间隔内汇总结果。

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

    这些方法已经存在,但除非您实际进行聚合,否则这将是您的应用程序性能最差的选项。而是在代码中进行转换。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-11
      • 1970-01-01
      • 2017-01-10
      • 2023-03-11
      • 2016-09-06
      • 1970-01-01
      • 2012-03-21
      • 2011-05-31
      相关资源
      最近更新 更多