在MongoDb中按15分钟的时间间隔分组结果

在MongoDb中按15分钟的时间间隔分组结果,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我有一个像这样的“状态”收藏- { _id: ObjectId("545a0b63b03dbcd1238b4567"), status: 1004, comment: "Rem dolor ipsam placeat omnis non. Aspernatur nobis qui nisi similique.", created_at: ISODate("2014-11-05T11:34:59.804Z") }, { _id: ObjectId("545

我有一个像这样的“状态”收藏-

{
    _id: ObjectId("545a0b63b03dbcd1238b4567"),
    status: 1004,
    comment: "Rem dolor ipsam placeat omnis non. Aspernatur nobis qui nisi similique.",
    created_at: ISODate("2014-11-05T11:34:59.804Z")
},
{
    _id: ObjectId("545a0b66b03dbcd1238b4568"),
    status: 1001,
    comment: "Sint et eos vero ipsa voluptatem harum. Hic unde voluptatibus et blanditiis quod modi.",
    created_at: ISODate("2014-11-05T11:35:02.814Z")
}
....
....

我需要从该集合中按15分钟的间隔对结果进行分组。有几种方法可以做到这一点

第一个是with,它允许您剖析文档中的“日期”值。特别是将“分组”作为主要目的:

db.collection.aggregate([
{“$组”:{
“_id”:{
“年”:{“$year”:“$created_at”},
“dayOfYear”:{“$dayOfYear”:“$created_at”},
“小时”:{“$hour”:“$created_at”},
“间隔”:{
“$subtract”:[
{“$minute”:“$created_at”},
{“$mod”:[{“$minute”:“$created_at”},15]}
]
}
}},
“计数”:{“$sum”:1}
}}
])
第二种方法是使用一个小技巧,当从另一个日期对象减去一个日期对象(或其他直接的数学运算)时,结果是一个数值,表示两个对象之间的历元时间戳毫秒。因此,只要使用历元日期,就可以得到历元毫秒表示。然后对间隔使用日期数学:

db.collection.aggregate([
{“$组”:{
“_id”:{
“$subtract”:[
{“$subtract”:[“$created_at”,新日期(“1970-01-01”)],
{“$mod”:[
{“$subtract”:[“$created_at”,新日期(“1970-01-01”)],
1000 * 60 * 15
]}
]
},
“计数”:{“$sum”:1}
}}
])
因此,这取决于分组间隔的输出格式。两者基本上表示相同的东西,并且有足够的数据在代码中重新构造为“日期”对象

您可以在分组
\u id
之后的“分组运算符”部分中添加任何其他内容。我只是用基本的“计数”例子来代替你自己关于你真正想做什么的任何真实陈述


MongoDB 4.x及以上版本 自最初编写日期聚合运算符以来,对其进行了一些添加,但在MongoDB 4.0中,将出现实际的“类型转换”,而不是使用BSON日期转换完成的基本数学技巧

例如,我们可以在此处使用和作为新助手:

db.collection.aggregate([
{“$组”:{
“_id”:{
“$toDate”:{
“$subtract”:[
{“$toLong”:“$created_at”},
{“$mod”:[{“$toLong”:“$created_at”},1000*60*15]}
]
}
},
“计数”:{“$sum”:1}
}}
])
这稍微短了一点,并且在定义管道时不需要将“epoch”值的外部BSON日期定义为常量,因此它对于所有语言实现都非常一致

这只是用于类型转换的两个“helper”方法,它们都与该方法相关联,该方法是一种“更长”的实现形式,允许对
null
或转换中的错误进行自定义处理

通过这种转换,甚至可以从主键的
ObjectId
获取
Date
信息,因为这将是“创建”日期的可靠来源:

db.collection.aggregate([
{“$组”:{
“_id”:{
“$toDate”:{
“$subtract”:[
{“$toLong”:{“$toDate”:“$_id”},
{“$mod”:[{“$toLong”:{“$toDate”:“$\u id”},1000*60*15]}
]
}
},
“计数”:{“$sum”:1}
}}
])
因此,这种转换的“铸造类型”可以是非常强大的工具

警告-
ObjectId
值仅限于内部时间值的精度,该值构成允许转换的部分数据。实际插入的“时间”很可能取决于正在使用的驾驶员。如果需要精度,仍然建议使用离散的BSON Date字段,而不是依赖
ObjectId


我喜欢这里的另一个答案,主要是因为使用了日期数学,而不是聚合日期运算符,这虽然有帮助,但也有点模糊

我想在这里添加的唯一一件事是,您还可以通过这种方法从聚合框架返回
Date
对象,而不是作为结果的“数字”时间戳。这只是在同样的原则上的一点额外的数学,使用:

db.collection.aggregate([
{“$组”:{
“_id”:{
“$add”:[
{“$subtract”:[
{“$subtract”:[“$current_date”,新日期(0)],
{“$mod”:[
{“$subtract”:[“$current_date”,新日期(0)],
1000 * 60 * 15
]}
] },
新日期(0)
]
},
“计数”:{“$sum”:1}
}}
])
这里JavaScript中的
日期(0)
构造函数以较短的形式表示相同的“纪元”日期,因为距纪元0毫秒就是纪元。但主要的一点是,当使用数字标识符对另一个BSON date对象进行“添加”时,所述条件的倒数是真的,最终结果实际上现在是一个
日期


所有驱动程序都将通过这种方法将本机
日期
类型返回到他们的语言。

对于mongo db.version()<3.0来说更漂亮一些

另一个有用的方法:

db.collection.aggregate([
{$group:{
_id:{
总时间:{
$dateToString:{格式:“%Y-%m-%dT%H”,日期:“$created_at”}
},
间隔:{$trunc:{$divide:[{$minute:$created_at“},15]}
},
}},
])
对于分钟、小时、白天的间隔更容易:

var format=“%Y-%m-%dT%H:%m”//1分钟
var format=“%Y-%m-%dT%H”//1小时
var format=“%Y-%m-%d”//一天
db.collection.aggregate([
{$group:{
_id:{$dateToString:{格式:格式,dat
db.collection.aggregate([
    {$match: {created_at:{$exists:1}}},
    {$group: {
        _id: {$add:[
            {$dayOfYear: "$created_at" },
            {$multiply: [{$year: "$created_at"}, 1000]}
        ]},
        count: {$sum: 1 }
    }},
    {$sort:{_id:-1}}
])
db.collection.aggregate([
    { "$group": {
      "_id": {
          "$toDate": {
              "$subtract": [
                  { "$toLong": { "$toDate": "$_id" }  },
                  { "$mod": [ { "$toLong": { "$toDate": "$_id" } }, 1000 * 60 * 15 ] }
              ]
          }
      },
      "count": { "$sum": 1 }
   }}
])