Hei*_*tet 41 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("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")
}
....
....
Run Code Online (Sandbox Code Playgroud)
我需要从该集合中获得15分钟间隔的结果.
Nei*_*unn 109
有几种方法可以做到这一点.
第一个是日期聚合运算符,它允许您剖析文档中的"日期"值.特别是"分组"作为主要意图:
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 }
}}
])
Run Code Online (Sandbox Code Playgroud)
第二种方法是使用一个小技巧,当从另一个日期对象中减去日期对象(或其他直接数学运算)时,结果是一个数值,表示两个对象之间的纪元时间戳毫秒.因此,只需使用纪元日期即可获得纪元毫秒表示.然后使用日期数学作为间隔:
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 }
}}
])
Run Code Online (Sandbox Code Playgroud)
因此,它取决于您希望分组间隔的输出格式类型.两者基本上代表相同的东西,并有足够的数据重新构建为代码中的"日期"对象.
在分组后,您可以在"分组运算符"部分中放置任何其他内容_id
.我只是使用基本的"计数"示例来代替您自己想要做的任何真实陈述.
自最初的写作以来,对日期聚合运算符进行了一些补充,但是从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 }
}}
])
Run Code Online (Sandbox Code Playgroud)
这有点短,并且不需要将"epoch"值的外部BSON日期定义为定义管道的常量,因此它对于所有语言实现都非常一致.
这些只是两种类型转换的"辅助"方法,它们都与$convert
方法相关联,这是一种"更长"的实现形式,允许自定义处理null
或转换错误.
甚至可以通过这种转换Date
从ObjectId
主键获取信息,因为这将是"创建"日期的可靠来源:
db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": { "$toDate": "$_id" } },
{ "$mod": [ { "$toLong": { "$toDate": "$_id" } }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
Run Code Online (Sandbox Code Playgroud)
因此,使用这种转换的"投射类型"可以是非常强大的工具.
Bla*_*ven 15
我喜欢这里的另一个答案,主要是使用日期数学而不是聚合日期操作符,虽然有用也可能有点模糊.
我想在这里添加的唯一内容是,您也可以Date
通过此方法从聚合框架返回一个对象,而不是作为结果的"数字"时间戳.这只是在相同原则上的一些额外数学,使用$add
:
db.collection.aggregate([
{ "$group": {
"_id": {
"$add": [
{ "$subtract": [
{ "$subtract": [ "$current_date", new Date(0) ] },
{ "$mod": [
{ "$subtract": [ "$current_date", new Date(0) ] },
1000 * 60 * 15
]}
] },
new Date(0)
]
},
"count": { "$sum": 1 }
}}
])
Run Code Online (Sandbox Code Playgroud)
在Date(0)
JavaScript中contructs这里表示在更短的形式相同的"时期"日期,如从历元0毫秒是划时代.但主要的一点是,当使用数字标识符完成对另一个BSON日期对象的"添加"时,所描述条件的反转为真,最终结果实际为现在为a Date
.
所有驱动程序都会Date
通过此方法将本机类型返回到其语言.
另一个有用的方法:
db.collection.aggregate([
{$group: {
_id: {
overallTime: {
$dateToString: { format: "%Y-%m-%dT%H", date: "$created_at" }
},
interval: { $trunc: { $divide: [{ $minute: "$created_at" }, 15 ]}}
},
}},
])
Run Code Online (Sandbox Code Playgroud)
对于min、hour、day间隔更容易:
var format = "%Y-%m-%dT%H:%M"; // 1 min
var format = "%Y-%m-%dT%H"; // 1 hour
var format = "%Y-%m-%d"; // 1 day
db.collection.aggregate([
{$group: {
_id: { $dateToString: { format: format, date: "$created_at" } },
}},
])
Run Code Online (Sandbox Code Playgroud)
小智 7
mongo db.version()<3.0更美观一点
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}}
])
Run Code Online (Sandbox Code Playgroud)
小智 6
聚合管道现在支持日期截断,例如:
{
$group: {
"_id": { "$dateTrunc": { date: "$created_at", unit: "minute", binSize: 15 } },
"count" : { $sum: 1 }
}
},
Run Code Online (Sandbox Code Playgroud)
您还可以在此处找到有关窗口函数和 dateTrunc 的有用信息