У меня есть набор пользовательских документов, где каждый пользователь может иметь произвольный набор свойств. Каждый пользователь связан с документом приложения. Вот пример пользователя:
{
"appId": "XXXXXXX",
"properties": [
{ "name": "age", "value": 30 },
{ "name": "gender", "value": "female" },
{ "name": "alive", "value": true }
]
}
Я хотел бы иметь возможность находить/подсчитывать пользователей на основе значений их свойств. Например, найдите всех пользователей для приложения X, у которых есть свойство Y > 10 и Z равно true.
У меня есть составной, мультикидный индекс в этой коллекции db.users.ensureIndex({ "appId": 1, "properties.name": 1, "properties.value": 1})
. Этот индекс хорошо работает для запросов с одним условием, например:
db.users.find({
appId: 'XXXXXX',
properties: {
$elemMatch: {
name: 'age',
value: {
$gt: 10
}
}
}
})
Вышеупомянутый запрос завершается в < 300 мс с коллекцией пользователей 1М. Однако, когда я пытаюсь добавить второе условие, производительность значительно ухудшается (7-8 с), а вывод explain()
указывает, что весь индекс сканируется для выполнения запроса ("nscanned" : 2752228
).
Запрос
db.users.find({
appId: 'XXXXXX',
properties: {
$all: [
{
$elemMatch: {
name: 'age',
value: {
$gt: 10
}
}
},
{
$elemMatch: {
name: 'alive',
value: true
}
}
]
}
})
Поясните
{
"cursor" : "BtreeCursor appId_1_properties.name_1_properties.value_1",
"isMultiKey" : true,
"n" : 256,
"nscannedObjects" : 1000000,
"nscanned" : 2752228,
"nscannedObjectsAllPlans" : 1018802,
"nscannedAllPlans" : 2771030,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 21648,
"nChunkSkips" : 0,
"millis" : 7425,
"indexBounds" : {
"appId" : [
[
"XXXXX",
"XXXXX"
]
],
"properties.name" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"properties.value" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"filterSet" : false
}
Я предполагаю, что это потому, что Mongo не может создать подходящие границы, так как я ищу как логические, так и целые значения.
Мой вопрос заключается в следующем: есть ли лучший способ структурирования моих данных или изменить мой запрос для повышения производительности и лучше использовать мой индекс? Можно ли поручить манго обрабатывать каждое условие отдельно, сгенерировать соответствующие границы, а затем выполнить пересечение результатов вместо сканирования всех документов? Или монго просто не подходит для этого типа использования?