5

我正在寻找这个,但我找不到任何有用的东西来解决我的问题。我想要的是在聚合期间从 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 运算符不允许负长度。有没有人有任何其他的解决方案?

4

1 回答 1

8

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

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

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

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

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

于 2014-09-06T03:46:06.610 回答