获得日期差异

时间:2017-08-09 15:34:09

标签: mongodb mongodb-query aggregation-framework

我在mongo中有一个多个日期的列表,我想找到每个日期之间的时间差(例如objectId 3和4之间的时间,objectId 4和5,objectId 5和6.我尝试了mongo&#39 ; s $减去,但它给出了我的答案,以毫秒为单位,转换时没有意义。另外,不应该是objectId 3的dateDiff值,因为它之前没有日期。< / p>

> db.collection.find({item:"1"})
{ "_id" : ObjectId("3"), "item" : "1", "date" : ISODate("2016-02-08T10:24:36Z") }
{ "_id" : ObjectId("4"), "item" : "1", "date" : ISODate("2016-02-13T10:24:36Z") }
{ "_id" : ObjectId("5"), "item" : "1", "date" : ISODate("2016-02-29T10:24:36Z") }
{ "_id" : ObjectId("6"), "item" : "1", "date" : ISODate("2016-03-13T10:24:36Z") }

> db.collection.aggregate([
   {$match:{item:"1"}},
   {$sort:{date:1}},
   {$project:{dateDiff:{$subtract:[new Date(),"$date"]}}}
])
{ "_id" : ObjectId("3"), "dateDiff" : NumberLong("18412790289") }
{ "_id" : ObjectId("4"), "dateDiff" : NumberLong("17980790289") }
{ "_id" : ObjectId("5"), "dateDiff" : NumberLong("16598390289") }
{ "_id" : ObjectId("6"), "dateDiff" : NumberLong("15302390289") }

2 个答案:

答案 0 :(得分:2)

您必须查看您尝试的语句,并了解您要求“数据库服务器”执行的操作是“从当前时间”中减去日期值,这是new Date()实际正在做的事情。这解释了您从尝试中获得的输出,因为该值不是“之前的文档日期”

如果你所追求的是前面每个项目和当前项目之间的日期差异,那么我真的不认为这是“数据库服务器”本身执行的任务。你要问的是,通过简单地处理光标并保持对前一个“日期”的引用然后简单地从当前减去它来更自然地解决这个问题:

var previousDate = false;
db.getCollection('collection').find().sort({ "item": 1, "date": 1 }).map( d => {
  var diff = (previousDate) ? NumberLong(d.date - previousDate) : 0;
  previousDate = d.date;
  return Object.assign(d,{ diff })
})

返回:

{
    "_id" : ObjectId("598b794c1b61b8b7a12329b4"),
    "item" : "1",
    "date" : ISODate("2016-02-08T10:24:36.000Z"),
    "diff" : 0.0
},
{
    "_id" : ObjectId("598b794c1b61b8b7a12329b5"),
    "item" : "1",
    "date" : ISODate("2016-02-13T10:24:36.000Z"),
    "diff" : NumberLong(432000000)
},
{
    "_id" : ObjectId("598b794c1b61b8b7a12329b6"),
    "item" : "1",
    "date" : ISODate("2016-02-29T10:24:36.000Z"),
    "diff" : NumberLong(1382400000)
},
{
    "_id" : ObjectId("598b794c1b61b8b7a12329b7"),
    "item" : "1",
    "date" : ISODate("2016-03-13T10:24:36.000Z"),
    "diff" : NumberLong(1123200000)
}

这通常是最好的事情,因为自然事件是“一个接一个”,这就是光标实际处理的内容。 MongoDB本身没有“引用前一个文档的值”的真正方法,唯一的方法就是将值强制转换为“数组”进行处理。

因此,在大多数现实世界中,像“数组”这样的处理实际上并不实用,实际上通过将值存储在任何大小的数组中都会超过16MB BSON限制。

如果您认为必须“在服务器上”执行此操作,那么最有效的用法是应用$reduce,在处理列表{{}}时可以访问“当前”和“之前已减少”的项目分别为{1}}和$$this

$$value

哪个输出

db.getCollection('collection').aggregate([
  { "$sort": { "item": 1, "date": 1 } },
  { "$group": {
    "_id": "$item",
    "diff": { "$push": "$date" }
  }},
  { "$addFields": {
    "diff": {
      "$map": {
        "input": {
          "$reduce": {
            "input": "$diff",
            "initialValue": [],
            "in": {
              "$concatArrays": [
                "$$value",
                [{ 
                  "date": "$$this", 
                  "diff": { 
                    "$cond": {
                      "if": { "$eq": [{ "$size": "$$value" }, 0] },
                      "then": 0,
                      "else": {
                        "$subtract": ["$$this", { "$arrayElemAt": ["$$value.date", -1] }]    
                      }
                    }   
                  }
                }]
              ]  
            }
          }
        },
        "as": "d",
        "in": "$$d.diff"
      }  
    }  
  }},
  { "$unwind": "$diff" }
])

请注意,由于$reduce喜欢它的其他语言对应物通常是“减少”结果,我们通过使用$concatArrays“加入”“前一个”和“当前”来使返回的结果成为一个数组“输出。

每个项目的基本过程(除第一项的逻辑外)是使用索引{ "_id" : "1", "diff" : 0.0 } { "_id" : "1", "diff" : NumberLong(432000000) } { "_id" : "1", "diff" : NumberLong(1382400000) } { "_id" : "1", "diff" : NumberLong(1123200000) } 通过$subtract $arrayElemAt之前的结果,这意味着“最后”的项目数组,来自使用$group通过之前的$push阶段收集的“当前”项目。

由于需要“上一个日期”,$reduce输出包含-1值以确定每个值之间的差异。然后,包装$map操作将提取实际的"date"值,该操作仅返回该属性的值,并返回到最终结果,然后按顺序处理数组$unwind将这些项目放回文件表格。

较少的管道阶段总是意味着更好的性能,因为每个阶段本质上都是“通过数据”并且需要时间。所以这里$group做“集合”,下一个阶段找到“差异”。这基本上就是操作,它只需要这两个阶段。

这有点“玩杂耍”,但比你可能做的要少得多,并且是实际解决“在服务器上”的最高效的方式。但这确实不是一个“服务器”问题,并且更适合简单地“按顺序处理光标”,就像最初显示的那样。

答案 1 :(得分:1)

使用新的var tween = KUTE.fromTo('#original', {path: '#original' }, { path: '#swimming' }, {morphPrecision:64, morphIndex:32, repeat:161803}).start(); ,您有效地将当前日期与相应日期字段中的日期进行比较。你想要做的是将不同文档中的值相互比较,这可以通过创建一些包含所有日期的辅助数组来实现。

这是一个有效的评论版本:

Date()