我必须在MongoDB中进行多次计数。我有这样的文档集合(大约150万个):
reportDocument
{
_id : Guid,
status : number (enum value),
name : string
}
具有自定义索引
{
name : 1,
status : 1
}
我的目标是按这样的名称获得一个计数器
{
inProgress : 3,
completed : 2,
canceled : 4
}
我有两种解决方法。第一个只是简单地使用count 3次
db.reports.count({name : "name", status : 2}) // for canceled, completed etc
并根据这些值形成计数器。此查询使用索引,并且应该可以快速运行,但是我必须从客户端发出3个请求。第二种选择是使用聚合框架。我有两个变体。
第一个
解释告诉我这是一个collscan,我认为这很糟糕,所以我将其修改为第二个
db.reports.aggregate([
{ "$facet": {
"inProgress": [
{ "$match" : {"name": "name", status : 0}},
{ "$count": "count" },
],
"completed": [
{ "$match" : {"name": "name", status : 1}},
{ "$count": "count" },
],
"canceled": [
{ "$match" : { "name": "name2", status : 2}},
{ "$count": "count" },
]
}},
{ "$project": {
"inProgress": { "$arrayElemAt": ["$inProgress.count", 0] },
"completed": { "$arrayElemAt": ["$completed.count", 0] },
"canceled": { "$arrayElemAt": ["$canceled.count", 0] }
}}
])
第二
此查询在$ match阶段使用索引,但是据我了解,聚合框架仅在从游标检索文档后才进行聚合,因此它将获取所有匹配的{ name : "name" }
文档并遍历所有这些文档而无需获取考虑到我的自定义索引(还包括有关状态的信息),对我来说听起来并不有效。
db.reports.aggregate([
{"$match" : {"name": "name"}},
{ "$facet": {
"inProgress": [
{ "$match" : { status : 0 }},
{ "$count": "count" },
],
"completed": [
{ "$match" : { status : 1}},
{ "$count": "count" },
],
"canceled": [
{ "$match" : { status : 2}},
{ "$count": "count" },
]
}},
{ "$project": {
"inProgress": { "$arrayElemAt": ["$inProgress.count", 0] },
"completed": { "$arrayElemAt": ["$completed.count", 0] },
"canceled": { "$arrayElemAt": ["$canceled.count", 0] }
}}
])
我无法在这些解决方案之间做出选择,也许还有其他解决方案。我想要一个查询,它可以充分利用我的自定义索引(其中包括有关状态的信息,似乎聚合没有使用它),并且执行速度与3个独立计数查询一样快。那么实现我的目标的最佳实践是什么?