У меня есть огромная коллекция документов, которая, вообще говоря, предназначена для хранения миллионов документов.
В общем, типичный документ может быть довольно сложным и динамичным, но есть несколько постоянных полей, которыедолжен присутствовать в каждом из них.Эти поля включают в себя: GlobalDeviceStatus
, ManualTests
, SemiAutomaticTests
, AutomaticTests
.Все три типа тестов представлены массивами объектов.Каждый такой объект может содержать довольно много полей, но опять же есть несколько постоянных.Это componentName
и componentTestStatus
.
{
"data": {
"globalDeviceStatus": false,
"qaOfficerID": 12121,
"ManualTests": [{
"componentName": "camera",
"componentTestStatus": true,
"x": 10
},
{
"componentName": "wifi",
"componentTestStatus": false,
"mnum": 711
}
],
"SemiAutomaticTests": [{
"componentName": "someComponent",
"componentTestStatus": true,
"someParameter": true
},
{
"componentName": "oneMoreComponent",
"componentTestStatus": false
}
],
"AutomaticTests": [{
"componentName": "anotherComponent",
"componentTestStatus": true
},
{
"componentName": "someVeryImportantComponent",
"componentTestStatus": false
}
]
},
"userID": 1
}
Каждый документ представляет собой тест.Если значение GlobalDeviceStatus
окажется равным false
, то проверка не пройдена.Это также означает, что его json должен содержать как минимум один отказавший компонент (тесты с GlobalDeviceStatus
, равным true
, наоборот, не содержат отказавших компонентов, что вполне логично).Что мне нужно, так это рассчитать количество сбоев для каждого компонента, поэтому в качестве выходных данных мне нужно что-то вроде этого:
{
"componentName": 120,
"someOtherComponentName": 31
}
Каждое componentName может принадлежать только одному типу теста.То есть, если в одном документе он находится в SemiAutomaticTests
тестах, он не может перейти на AutomaticTests
в другом.
Для таких вычислений я использую следующий канал Монго:
COUNT_CRASHES = [
{
"$match": {
"$or": [{
"data.ManualTests.componentTestStatus": false
}, {
"data.AutomaticTests.componentTestStatus": false
}, {
"data.SemiAutomaticTests.componentTestStatus": false
}]
}
}, {
"$project": {
"tests": {
"$concatArrays": [{
"$filter": {
"input": "$data.ManualTests",
"as": "mt",
"cond": {
"$eq": ["$$mt.componentTestStatus", false]
}
}
}, {
"$filter": {
"input": "$data.AutomaticTests",
"as": "at",
"cond": {
"$eq": ["$$at.componentTestStatus", false]
}
}
}, {
"$filter": {
"input": "$data.SemiAutomaticTests",
"as": "st",
"cond": {
"$eq": ["$$st.componentTestStatus", false]
}
}
}]
}
}
}, {
"$unwind": "$tests"
}, {
"$group": {
"_id": "$tests.componentName",
"count": {
"$sum": 1
}
}
}
]
Он возвращает данные в формате, отличном от указанного выше, но это не так важно, что действительно важно сейчас, это то, что для возврата требуется около 7 секунд, а иногда и в два раза больше (~ 14 секунд).Это с 350 тыс. Документов в БД.
Я бы хотел максимально сократить время.