有几种方法可以做到这一点。
第一个是Date Aggregation Operators,它允许您剖析文档中的“日期”值。专门针对“分组”作为主要意图:
db.collection.aggregate([
{ "$group": {
"_id": {
"year": { "$year": "$created_at" },
"dayOfYear": { "$dayOfYear": "$created_at" },
"hour": { "$hour": "$created_at" },
"interval": {
"$subtract": [
{ "$minute": "$created_at" },
{ "$mod": [{ "$minute": "$created_at"}, 15] }
]
}
}},
"count": { "$sum": 1 }
}}
])
第二种方法是使用一个小技巧,即从另一个日期对象中减去一个日期对象(或其他直接数学运算),然后结果是一个表示两个对象之间的纪元时间戳毫秒的数值。因此,只需使用纪元日期即可获得纪元毫秒表示。然后使用日期数学作为间隔:
db.collection.aggregate([
{ "$group": {
"_id": {
"$subtract": [
{ "$subtract": [ "$created_at", new Date("1970-01-01") ] },
{ "$mod": [
{ "$subtract": [ "$created_at", new Date("1970-01-01") ] },
1000 * 60 * 15
]}
]
},
"count": { "$sum": 1 }
}}
])
所以这取决于你想要分组间隔的输出格式。两者基本上代表相同的事物,并且有足够的数据在您的代码中重新构造为“日期”对象。
您可以在分组_id 之后的“分组运算符”部分中添加任何其他内容。我只是使用基本的“计数”示例来代替你自己关于你真正想做的任何真实陈述。
MongoDB 4.x 及更高版本
自最初编写以来,日期聚合运算符添加了一些内容,但从 MongoDB 4.0 开始,将有实际的“真正的类型转换”,而不是此处使用 BSON 日期转换完成的基本数学技巧。
例如,我们可以在这里使用$toLong 和$toDate 作为新的助手:
db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": "$created_at" },
{ "$mod": [ { "$toLong": "$created_at" }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
这有点短,并且不需要将“epoch”值的外部 BSON 日期定义为定义管道时的常量,因此它对于所有语言实现都非常一致。
这些只是类型转换的“辅助”方法中的两个,它们都与$convert 方法相关联,这是一种“更长”的实现形式,允许对null 进行自定义处理或转换错误。
甚至可以通过这种转换从主键的ObjectId 中获取Date 信息,因为这将是“创建”日期的可靠来源:
db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": { "$toDate": "$_id" } },
{ "$mod": [ { "$toLong": { "$toDate": "$_id" } }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
因此,使用这种转换的“转换类型”可能是非常强大的工具。
警告 - ObjectId 值仅限于精确到 秒,仅适用于构成其数据的一部分的内部时间值,允许 $toDate 转换。实际插入的“时间”很可能取决于使用的驱动程序。在需要 精度 的地方,仍然建议使用离散的 BSON 日期字段,而不是依赖 ObjectId 值。