Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mongodb 获取运行日期的差异_Mongodb_Mongodb Query_Aggregation Framework - Fatal编程技术网

Mongodb 获取运行日期的差异

Mongodb 获取运行日期的差异,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我在mongo有一个多个日期的列表,我想找出每个日期之间的时差(例如,objectId 3和4、objectId 4和5、objectId 5和6之间的时间。我尝试了mongo的$subtract,但它以毫秒为单位给出了答案,转换后没有意义。此外,objectId 3不应该有dateDiff值,因为之前没有日期 > db.collection.find({item:"1"}) { "_id" : ObjectId("3"), "item" : "1", "date" : ISODate("

我在mongo有一个多个日期的列表,我想找出每个日期之间的时差(例如,objectId 3和4、objectId 4和5、objectId 5和6之间的时间。我尝试了mongo的$subtract,但它以毫秒为单位给出了答案,转换后没有意义。此外,objectId 3不应该有dateDiff值,因为之前没有日期

> 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") }
使用新的
Date()
可以有效地将当前的日期与各自的日期字段中的日期进行比较。您要做的是将不同文档中的值相互比较,这可以通过创建包含所有日期的帮助器数组来实现

以下是一个有效的注释版本:

db.collection.aggregate([{
    $match: {
        item: "1" // not really needed but I guess it makes sense in your specific case so I leave it here
    }
},
{
    $sort: {
        date: 1 // we need to sort in order to find the next bigger date
    }
},
{
    $group: {
        "_id": "$item", // for every item...
        "date": { $push: "$date" }, // ...we create two identical arrays (could be done using another $project stage, too)
        "allDates": { $push: "$date" } // ...that each contain all dates that we find for our item
    }
},
{
    $unwind: "$date" // this will flatten one of the two created date arrays
},
{
    $project: {
        "date": 1,
        "followingDate": {
            $arrayElemAt: [
                "$allDates", // here we use the second (remaining) date array to find the next date...
                { $add: [ { $indexOfArray: [ "$allDates", "$date" ] }, 1 ] } // ...which needs to sit in that sorted array at the position of the element we're looking at right now + 1
            ]
        }
    }
},
{
    // now, we simply create a nice result document with various ways of looking at the date differences
    $project: {
        "date": 1,
        "followingDate": 1,
        "differenceInMilliseconds": {
            $subtract: [ "$followingDate", "$date" ]
        },
        "differenceInSeconds": {
            $divide: [ { $subtract: [ "$followingDate", "$date" ] }, 1000 ]
        },
        "differenceInMinutes": {
            $divide: [ { $subtract: [ "$followingDate", "$date" ] }, 1000 * 60 ]
        },
        "differenceInHours": {
            $divide: [ { $subtract: [ "$followingDate", "$date" ] }, 1000 * 60 * 60 ]
        },
        "differenceInDays": {
            $divide: [ { $subtract: [ "$followingDate", "$date" ] }, 1000 * 60 * 60 *24 ]
        }
    }
}])

您必须查看您尝试的语句,并理解您要求“数据库服务器”所做的只是“从当前时间中提取日期值”,这就是
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限制

但是,如果您认为必须“在服务器上”执行此操作,则最有效的使用方法是,在将列表分别作为
$$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" }
])
哪个输出

{ "_id" : "1", "diff" : 0.0 }
{ "_id" : "1", "diff" : NumberLong(432000000) }
{ "_id" : "1", "diff" : NumberLong(1382400000) }
{ "_id" : "1", "diff" : NumberLong(1123200000) }
请注意,因为与其他语言的对应部分一样,它通常是关于“减少”一个结果,所以我们通过使用“连接”“上一个”和“当前”输出,将返回的结果设置为一个数组

每个项目的基本过程(第一个项目的逻辑除外)是通过使用索引
-1
(表示数组的“最后一个”项目)从通过前一阶段收集的“当前”项目处理到上一个结果

由于需要“上一个日期”,因此输出包括
“date”
值,以确定每个日期之间的差异。实际的
“diff”
然后通过包装操作提取值,包装操作仅返回该属性的值,并得出最终结果,然后处理数组,以便将项目放回文档形式

更少的管道阶段总是意味着更好的性能,因为每个阶段本质上都是一个“数据传递”,这需要时间。所以这里进行“收集”,下一个阶段发现“差异”。这基本上就是操作,实际上只需要这两个阶段

这有点“杂耍”,但比你可能做的要少很多,而且是真正解决“服务器上”问题的最有效的方法。但这实际上不是“服务器”问题,更适合于简单地“按顺序处理光标”,就像最初显示的那样