Я должен сделать несколько подсчетов в MongoDB.У меня есть коллекция документов (около 1,5 миллионов), например:
reportDocument
{
_id : Guid,
status : number (enum value),
name : string
}
с пользовательским индексом
{
name : 1,
status : 1
}
Моя цель - получить счетчик для каждого имени, подобного этому
{
inProgress : 3,
completed : 2,
canceled : 4
}
У меня есть два обходных пути.Во-первых, просто используйте счет 3 раза
db.reports.count({name : "name", status : 2}) // for canceled, completed etc
и сформируйте счетчик из этих значений.Этот запрос использует индекс и должен работать быстро, но я должен сделать 3 запроса со стороны клиента.Второй вариант - использование структуры агрегации.У меня есть два варианта.
1-й
Объясните мне, что это коллскан, что, на мой взгляд, плохо, поэтому я изменил это во второй
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] }
}}
])
2nd
Этот запрос использует индекс на этапе $ 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 отдельных запроса подсчета.Так какова лучшая практика для достижения моих целей?