Mongodb 时间间隔内的Mongo聚合

Mongodb 时间间隔内的Mongo聚合,mongodb,aggregation-framework,Mongodb,Aggregation Framework,我在mongo集合中存储了一些日志数据,其中包括作为请求id的基本信息以及添加到集合中的时间,例如: { "_id" : ObjectId("55ae6ea558a5d3fe018b4568"), "request_id" : "030ac9f1-aa13-41d1-9ced-2966b9a6g5c3", "time" : ISODate("2015-07-21T16:00:00.00Z") } 我想知道是否可以使用聚合框架来聚合一些统计数据。我想获得在过去X小时内每N

我在mongo集合中存储了一些日志数据,其中包括作为请求id的基本信息以及添加到集合中的时间,例如:

{
    "_id" : ObjectId("55ae6ea558a5d3fe018b4568"),
    "request_id" : "030ac9f1-aa13-41d1-9ced-2966b9a6g5c3",
    "time" : ISODate("2015-07-21T16:00:00.00Z")
}
我想知道是否可以使用聚合框架来聚合一些统计数据。我想获得在过去X小时内每N分钟间隔内创建的对象的计数

因此,我在过去1小时内每隔10分钟需要的输出应该如下所示:

{ "_id" : 0, "time" : ISODate("2015-07-21T15:00:00.00Z"), "count" : 67 }
{ "_id" : 0, "time" : ISODate("2015-07-21T15:10:00.00Z"), "count" : 113 }
{ "_id" : 0, "time" : ISODate("2015-07-21T15:20:00.00Z"), "count" : 40 }
{ "_id" : 0, "time" : ISODate("2015-07-21T15:30:00.00Z"), "count" : 10 }
{ "_id" : 0, "time" : ISODate("2015-07-21T15:40:00.00Z"), "count" : 32 }
{ "_id" : 0, "time" : ISODate("2015-07-21T15:50:00.00Z"), "count" : 34 }
我会用它来获取图表的数据

任何建议都将不胜感激

像这样的

pipeline = [
    {"$project":
        {"date": {
            "year": {"$year": "$time"},
            "month": {"$month": "$time"},
            "day": {"$dayOfMonth": "$time"},
            "hour": {"$hour": "$time"},
            "minute": {"$subtract": [
                {"$minute": "$time"},
                {"$mod": [{"$minute": "$time"}, 10]}
            ]}
        }}
    },
    {"$group": {"_id": "$date", "count": {"$sum": 1}}}
]
例如:

> db.foo.insert({"time": new Date(2015,  7, 21, 22, 21)})
> db.foo.insert({"time": new Date(2015,  7, 21, 22, 23)})
> db.foo.insert({"time": new Date(2015,  7, 21, 22, 45)})
> db.foo.insert({"time": new Date(2015,  7, 21, 22, 33)})
> db.foo.aggregate(pipeline)
和输出:

{ "_id" : { "year" : 2015, "month" : 8, "day" : 21, "hour" : 20, "minute" : 40 }, "count" : 1 }
{ "_id" : { "year" : 2015, "month" : 8, "day" : 21, "hour" : 20, "minute" : 20 }, "count" : 2 }
{ "_id" : { "year" : 2015, "month" : 8, "day" : 21, "hour" : 20, "minute" : 30 }, "count" : 1 }

用指针代替具体答案。您可以非常轻松地使用。每10分钟会有点棘手,但可能会有一些争吵。然而,在大型数据集上,聚合将非常缓慢

我建议提取插入后的会议记录

{
    "_id" : ObjectId("55ae6ea558a5d3fe018b4568"),
    "request_id" : "030ac9f1-aa13-41d1-9ced-2966b9a6g5c3",
    "time" : ISODate("2015-07-21T16:00:00.00Z"),
    "minutes": 16
}
即使加上四分位数和六分位数,或者N可能是什么,听起来非常荒谬

{
    "_id" : ObjectId("55ae6ea558a5d3fe018b4568"),
    "request_id" : "030ac9f1-aa13-41d1-9ced-2966b9a6g5c3",
    "time" : ISODate("2015-07-21T16:00:00.00Z"),
    "minutes": 16,
    "quartile: 1,
    "sextile: 2,
}
首先,试着在会议记录上做一个简单的练习。不做天花板和地板。但请注意


根据哪种输出格式最适合您的需要,有几种方法可以实现这一点。主要注意的是,对于它本身,您实际上无法返回一些“强制转换”为日期的内容,但您可以在API中处理结果时获得易于重构为
date
对象的值

第一种方法是使用聚合框架可用的:

db.collection.aggregate([
{“$match”:{
“时间”:{“$gte”:开始日期,$lt:结束日期}
}},
{“$组”:{
“_id”:{
“年”:{“$year”:“$time”},
“dayOfYear”:{“$dayOfYear”:“$time”},
“小时”:{“$hour”:“$time”},
“分钟”:{
“$subtract”:[
{“$minute”:“$time”},
{“$mod”:[{“$minute”:“$time”},10]}
]
}
},
“计数”:{“$sum”:1}
}}
])
它为
\u id
返回一个复合键,其中包含“日期”所需的所有值。或者,如果总是在一个“小时”内,则只需使用“分钟”部分,并根据所选范围的
startDate
计算出实际日期

或者,您可以使用普通的“日期数学”来获取“epoch”之后的毫秒数,它可以再次直接输入到日期构造函数

db.collection.aggregate([
{“$match”:{
“时间”:{“$gte”:开始日期,$lt:结束日期}
}},
{“$组”:{
“_id”:{
“$subtract”:[
{“$subtract”:[“$time”,新日期(0)],
{“$mod”:[
{“$subtract”:[“$time”,新日期(0)],
1000 * 60 * 10
]}
]
},
“计数”:{“$sum”:1}
}}
])
在所有情况下,你不想做的就是在实际应用之前使用。作为一个“管道阶段,
$project
必须“循环”选择所有文档并“转换”内容

这需要时间,并添加到查询的执行总数中。您只需直接应用于
$组
,如图所示

或者,如果您对返回的
Date
对象非常“纯粹”,而不进行后期处理,那么您可以始终使用,因为JavaScript函数实际上允许将其作为日期进行重铸,但速度比聚合框架慢,当然也没有光标响应:

db.collection.mapReduce(
函数(){
var日期=新日期(
this.time.valueOf()
-(此.time.valueOf()%(1000*60*10))
);
发出(日期1);
},
功能(键、值){
返回Array.sum(值);
},
{“out”:{“inline”:1}
)
不过,您最好使用聚合,因为转换响应非常简单:

db.collection.aggregate([
{“$match”:{
“时间”:{“$gte”:开始日期,$lt:结束日期}
}},
{“$组”:{
“_id”:{
“年”:{“$year”:“$time”},
“dayOfYear”:{“$dayOfYear”:“$time”},
“小时”:{“$hour”:“$time”},
“分钟”:{
“$subtract”:[
{“$minute”:“$time”},
{“$mod”:[{“$minute”:“$time”},10]}
]
}
},
“计数”:{“$sum”:1}
}}
]).forEach(功能(文档){
单据号=新日期(单据号);
printjson(doc);
})

然后,您可以使用real
Date
对象进行间隔分组输出。

操作员可以轻松完成此操作。在实际项目之前使用组的绝妙技巧是,如果在组之前使用,项目将在所有文档中循环运行,这一点很好。我想在这里实现的一件事(我已经更新了我的问题)是,当我将空间隔(不包括任何对象的间隔)传递给图形框架时,实际上在结果中得到0的计数。这将节省解析时间,并将其添加到使用数据的实际代码中。“这是可以实现的吗?”杰罗姆·沃尔特斯说,这真的不是一件明智的事情。如果你仔细想想,你只能对“存在”的键进行真正的“求和”。因此,虽然“可能”在该范围内输入每个“可能”键,但实际上并不实用,因为您要输入一个包含所有这些键的变量。明智的做法是将结果与API代码中的空白预期范围“组合”,而不是将所有这些值“扔”到服务器上。这同样适用于同一事物的SQL变体。仅仅因为你“能”并不意味着你“应该”。@JeromeWalters也“改变你的问题”,所以它本质上与你所问的“不同”。在这里不太受欢迎。如果一个答案让你找到另一个问题