Запрос MongoDB с использованием встроенного документа в качестве ключа - PullRequest
5 голосов
/ 07 июля 2011

Короткая версия:

Если у меня есть индекс {"category": 1} и документ {"category": {type: "memory", class: "DDR400"}, как я могу выполнить запрос, например {"category.type": "memory"}, который использует мой индекс?

Длинная версия:

В MongoDB я хочу использовать встроенный документ в качестве ключа для индекса.

Например, у меня могут быть такие документы, как этот (для гипотетической базы данных продуктов):

{"category": {"type": "hard-drive", "form_factor": "2.5in", "size": "500GB"}, ...}
{"category": {"type": "hard-drive", "form_factor": "3.5in", ...}, ...}
{"category": {"type": "memory", "class": "DDR400", ...}, ...}

Для приведенных выше примеров я мог бы захотеть выполнить такие запросы, как:

{"category.type": "hard-drive"}
{"category.type": "hard-drive", "category.form_factor": "2.5in"}
{"category.type": "memory"}
{"category.type": "memory", "category.class": "DDR400"}

У меня проблемы с созданием индекса. Документ в http://www.mongodb.org/display/DOCS/Indexes#Indexes-DocumentsasKeys описывает два варианта:

Первый вариант - создать составной индекс, например { "category.type": 1, "category.class": 1 }. Это не очень хорошо подходит для моего случая, поскольку у меня может быть много разных типов подкатегорий.

Второй вариант - использовать документ в качестве ключа: { "category": 1 }. Теперь запрос, такой как {"category": {"type": "memory", "class": "DDR400"}}, будет использовать индекс, но {"category": {"type": "memory"}} ничего не даст, а {"category.type": "memory"} не будет использовать индекс. Есть ли способ сделать запрос с использованием этого индекса, который бы дал те же результаты, что и {"category.type": "memory"}?

Я подозреваю, что запрос, использующий что-то вроде {"category" {"$gt": ..., "$lt": ...}, должен работать, но что я должен поместить в пробелы?

Ответы [ 2 ]

3 голосов
/ 07 июля 2011

Создание отдельного индекса для category.type (возможно, в дополнение к category) кажется наилучшим вариантом.

Вы можете использовать запрос диапазона с $gt и $lt. Они будут работать с двоичным представлением внедренного объекта, который работает только для первого (в порядке хранения) поля, и только если это первое поле одинаково во всех документах, поэтому оно не очень гибкое и его легко разбить.

   {"category"  : {"$gt": {"type": "memory"},  "$lt": {"type": "memoryX" } } }

«memoryX» здесь служит точкой отсечения: все с «памятью» будет сортировать до этого.

Обратите внимание, что для этого необходимо, чтобы поле "type" было первым в двоичном представлении для всех документов, в которых оно есть. Он также работает ТОЛЬКО для поля «тип» (нет возможности запрашивать другие поля в первой позиции, вы должны выбрать одно заранее), таким образом, вы практически не получаете преимущества над выделенным индексом «category.type» (просто пробел) экономии).

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

Это поддерживается и стабильно. Многие из шардинга / репликации внутренние компоненты используют значения _id, которые являются встроенными документами.

Единственное, на что следует обратить внимание, это упорядочить ключи в встроенный элемент Они отсортированы по их двоичному представлению так {x: 1, y: 1} отличается от {y: 1, x: 1} и сортируется по-разному. Не только они отсортированы по-разному, это разные значения. Немного языки всегда сортируют ключи в словаре / хэше / карте по умолчанию.

Опять же, рассмотрите возможность создания дополнительных индексов для полей, которые вам нужны.

В моем случае мне нужно будет только запросить «a», «a, b» или «a, b, c» или «a, x, y», где документы, содержащие x, никогда не содержат «b». 'или' c '

Это, вероятно, сработало бы тогда. Я бы все же сделал два составных индекса a,b и a,x. Или, может быть, просто b и x. Учитывая, что документ содержит b или x, вы, вероятно, уже эффективно отфильтровали ненужные документы в отношении a (form_factor = 2.5in уже говорит о том, что это жесткий диск, класс = DDR400 уже делает его памятью ). И после фильтрации по a,b вам может не понадобиться индекс для дальнейшего углубления до c.

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

2 голосов
/ 07 июля 2011

Если есть одно базовое свойство, которое вы ищете для каждого «типа», просто добавьте также как отдельное поле и создайте составной индекс, например:

{"category": {"type": "hard-drive", "form_factor": "2.5in", "searchfield: "2.5in", ...}, ...}
{"category": {"type": "memory", "class": "DDR400", searchfield: "DDR400", ...}, ...}

Если есть несколько полей, которые вы ищете, но значения для этих полей отличаются, вы можете добавить значения в виде тегов и снова создать составной ключ:

{"category": {"type": "hard-drive", "form_factor": "2.5in", "size": "500GB", "tags": ["2.5in", "500GB"]}, ...}
{"category": {"type": "memory", "class": "DDR400", "tags": ["DDR400"], ...}, ...}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...