Индексирование запросов позиции массива MongoDB

Я хотел бы создать индекс, который поддерживает запросы к определенным позициям элементов массива.

Даны несколько миллионов документов с массивами значений:

db.foo.insert({ array: [true, false, null, true] })
db.foo.insert({ array: [false, null, true, true] })

Я хочу найти документы с true в позиции 2.

db.foo.find({ "array.2": true })

Если я создам многоключевой индекс:

db.foo.createIndex({ array: 1 })

Индекс поддерживает запросы формы { "array": true } (поиск всех элементов массива), но не { "array.2": true } (поиск определенного элемента массива).

В документации говорится: "MongoDB создает ключ индекса для каждого элемента в массиве ", поэтому я ожидал, что если я создам индекс для поля array, он будет использоваться для запросов к array.0, array.1, array.2 и т. д. Есть ли какой-то трюк, чтобы заставить это работать?


person MZS    schedule 06.03.2018    source источник


Ответы (1)


Многоключевой индекс MongoDB индексирует только значения массива, а не положение указанного значения в массиве.

Сказав это, есть один возможный обходной путь, чтобы сделать то, что вам нужно.

Вместо того, чтобы хранить только значение массива, вам нужно будет сохранить «ключ», показывающий положение элемента. Используя ваш пример:

> db.test.find()
{
  "_id": 0,
  "a": [
    {"k": 0, "v": true},
    {"k": 1, "v": false},
    {"k": 2, "v": null},
    {"k": 3, "v": true}
  ]
}
{
  "_id": 1,
  "a": [
    {"k": 0, "v": false},
    {"k": 1, "v": null},
    {"k": 2, "v": true},
    {"k": 3, "v": true}
  ]
}

Обратите внимание, что в приведенном выше примере я использую вложенные документы с полем k для обозначения «позиции массива» и полем v для хранения «элемента массива».

Затем вы можете создать индекс, который индексирует оба поля:

db.test.createIndex({'a.k':1, 'a.v':1})

И запрос должен использовать оператор $elemMatch, чтобы убедиться, что весь поддокумент совпадает. Допустим, вы ищете k из 2 и v из true:

> db.test.find({a: {$elemMatch: {k:2, v:true}}})
{
  "_id": 1,
  "a": [
    {"k": 0, "v": false},
    {"k": 1, "v": null},
    {"k": 2, "v": true},
    {"k": 3, "v": true}
  ]
}

Одним из недостатков этого подхода является то, что вам нужно самостоятельно заниматься ведением домашнего хозяйства в отношении поля k. Вставка в массив немного сложнее, так как вам нужно знать наибольшее значение k перед выполнением $push, если вы хотите рассматривать k как индекс массива.

person kevinadi    schedule 08.03.2018