我有一个记录所有用户操作的系统,如日志系统。我想执行一个聚合,按照其id对所有用户进行分组,并创建一个包含其操作的列表。
使用 110M文档的数据库,其中包含注册用户操作的以下结构:
user_action
{
id_user: ObjectId(...),
created_at: Date(...),
action: {object},
}
(id_user和created_at都有索引。)
以下聚合尝试按给定日期对所有用户操作进行分组:
db.user_action.aggregate([
{ '$match': {'created_at': { $gte:ISODate("2016-06-05"), $lt:ISODate("2016-06-06")}}},
{ '$group': {
'_id' :{'id_user': '$id_user'},
actions: {
$push: '$action'
}
}}])
此汇总需要 2h和3h完成,但当天只有~3M文档:
db.count({'created_at': { $gte:ISODate("2016-06-05"), $lt:ISODate("2016-06-06")}})
2,7 M
(计数持续5秒执行)
汇总结果如下:
{
id_user: ObjectId(...),
date: day_requested,
actions:[action, action, ...]
}
汇总解释说查询正在使用IXSCAN。
{
"waitedMS" : NumberLong(0),
"stages" : [
{
"$cursor" : {
"query" : {
"created_at" : {
"$gte" : ISODate("2016-06-05T00:00:00Z"),
"$lt" : ISODate("2016-06-06T00:00:00Z")
}
},
"fields" : {
"action" : 1,
"id_user" : 1,
"_id" : 0
},
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "database1.collection1",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"created_at" : {
"$lt" : ISODate("2016-06-06T00:00:00Z")
}
},
{
"created_at" : {
"$gte" : ISODate("2016-06-05T00:00:00Z")
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"created_at" : -1
},
"indexName" : "created_at",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"created_at" : [
"(new Date(1465171200000), new Date(1465084800000)]"
]
}
}
},
"rejectedPlans" : [ ]
}
}
},
{
"$group" : {
"_id" : {
"id_user" : "$id_user"
},
"actions" : {
"$push" : "$action"
}
}
}
],
"ok" : 1
}
如果我使用$限制管道而不是$ match,则查询最后 1 minut而不是3hours 。上一个查询有什么问题吗? 如何在合理的时间内执行该大小的聚合?
提前谢谢