Запросы Mango
Помимо представлений map/reduce, CouchDB поддерживает гибкую систему запросов под названием Mango.
Mango состоит из двух основных понятий:
Селекторы — это запросы, которые передаются конечным точкам Mango
Индексы — это специализированные документы дизайна, используемые в запросах Mango
Для работы с этими понятиями предусмотрено несколько важных конечных точек:
POST /{db}/_find, выполняющая запросPOST /{db}/_explain, описывающая выполнение запросаGET /{db}/_indexиPOST /{db}/_index, управляющие индексами
Селекторы
Селекторы задаются объектом JSON, описывающим интересующие документы. В этой структуре можно применять условную логику с помощью полей со специальными именами.
Хотя селекторы имеют некоторое сходство с документами запросов MongoDB, это сходство обусловлено общей целью и не обязательно распространяется на функциональность или результат.
Предупреждение
Хотя CouchDB без проблем хранит практически любые данные JSON, Mango имеет ограничения на то, с чем он может работать:
Пустые имена полей (
"") нельзя использовать в запросах («В одном или нескольких условиях отсутствует имя поля»).Имена полей, начинающиеся с
$, необходимо экранировать с помощью\(например,\$foo) («Недопустимый оператор: $»).
Основы селекторов
Для простого синтаксиса селектора необходимо указать одно или несколько полей и соответствующие значения, требуемые для этих полей. Этот селектор находит все документы, у которых поле "director" имеет значение "Lars von Trier".
{
"director": "Lars von Trier"
} Простой селектор, проверяющий определённые поля:
"selector": {
"title": "Live And Let Die"
},
"fields": [
"title",
"cast"
] Селектор с двумя полями
Этот селектор находит любой документ, в котором поле name содержит "Paul", а поле location имеет значение "Boston".
{
"name": "Paul",
"location": "Boston"
} Вложенные поля
Более сложный селектор позволяет указать значения полей вложенных объектов, или подполей. Например, для указания поля и подполя можно использовать стандартную структуру JSON.
Пример селектора поля и подполя со стандартной структурой JSON:
{
"imdb": {
"rating": 8
}
} Эквивалентная краткая запись использует точечную нотацию, объединяющую имена поля и подполя в одно имя.
{
"imdb.rating": 8
} Операторы
Операторы обозначаются префиксом в виде знака доллара ($) в имени поля.
В синтаксисе селекторов есть два основных типа операторов:
Операторы объединения
Операторы условий
Как правило, операторы объединения применяются на верхнем уровне выборки. Они используются для объединения условий или создания комбинаций условий в одном селекторе.
Каждый явный оператор имеет вид:
{
"$operator": argument
} Селектор без явного оператора считается использующим неявный оператор. Конкретный неявный оператор определяется структурой выражения селектора.
Неявные операторы
Существует два неявных оператора:
Равенство
И
В селекторе любое поле, содержащее значение JSON без операторов, считается условием равенства. Неявная проверка равенства также применяется к полям и подполям.
Любой объект JSON, который не является аргументом оператора условия, подразумевает оператор $and для каждого поля.
В следующем примере оператор используется для поиска любого документа, в котором значение поля "year" больше 2010:
{
"year": {
"$gt": 2010
}
} В этом примере в подходящем документе должно быть поле "director", значение которого должно точно равняться "Lars von Trier".
{
"director": "Lars von Trier"
} Оператор равенства также можно указать явно.
{
"director": {
"$eq": "Lars von Trier"
}
} В следующем примере с подполями в подходящем документе должно быть поле "imdb" с подполем "rating", значение которого должно равняться 8.
Пример неявного оператора, применённого к проверке подполя:
{
"imdb": {
"rating": 8
}
} И здесь оператор равенства можно указать явно.
{
"imdb": {
"rating": { "$eq": 8 }
}
} Пример использования оператора $eq с базой данных, индексированной по полю "year":
{
"selector": {
"year": {
"$eq": 2001
}
},
"sort": [
"year"
],
"fields": [
"year"
]
} В этом примере поле "director" должно присутствовать и содержать значение "Lars von Trier", а поле "year" должно существовать и иметь значение 2003.
{
"director": "Lars von Trier",
"year": 2003
} Оператор $and и оператор равенства можно указать явно.
Пример явного использования операторов $and и $eq:
{
"$and": [
{
"director": {
"$eq": "Lars von Trier"
}
},
{
"year": {
"$eq": 2003
}
}
]
} Выбор неявной или явной формы полностью зависит от вас. Неявную форму немного проще записывать вручную. Явную форму немного проще использовать, если вы программно формируете селекторы. Результат будет одинаковым.
Явные операторы
Все операторы, кроме «Равенства» и «И», необходимо указывать явно.
Операторы объединения
Операторы объединения используются для объединения селекторов. Помимо распространённых логических операторов, встречающихся в большинстве языков программирования, существуют три оператора объединения ($all, $elemMatch и $allMatch), помогающие работать с массивами JSON, а также оператор для работы с картами JSON ($keyMapMatch).
Оператор объединения принимает один аргумент. Аргументом может быть другой селектор или массив селекторов.
Список операторов объединения:
Оператор | Аргумент | Назначение |
|---|---|---|
| Массив | Совпадение, если совпадают все селекторы в массиве. |
| Массив | Совпадение, если совпадает любой селектор в массиве. Все селекторы должны использовать один и тот же индекс. |
| Селектор | Совпадение, если заданный селектор не совпадает. |
| Массив | Совпадение, если ни один из селекторов в массиве не совпадает. |
| Массив | Совпадение со значением-массивом, если оно содержит все элементы массива-аргумента. |
| Селектор | Находит и возвращает все документы, содержащие поле-массив хотя бы с одним элементом, соответствующим всем заданным критериям запроса. |
| Селектор | Находит и возвращает все документы, содержащие поле-массив, все элементы которого соответствуют всем заданным критериям запроса. |
| Селектор | Находит и возвращает все документы, содержащие карту хотя бы с одним ключом, соответствующим всем заданным критериям запроса. |
| Строка | Выполняет полнотекстовый поиск |
Оператор $and
Оператор $and применяется к двум полям:
{
"selector": {
"$and": [
{
"title": "Total Recall"
},
{
"year": {
"$in": [1984, 1991]
}
}
]
},
"fields": [
"year",
"title",
"cast"
]
} Оператор $and находит совпадение, если совпадают все селекторы в массиве. Ниже приведён пример с использованием первичного индекса (_all_docs):
{
"$and": [
{
"_id": { "$gt": null }
},
{
"year": {
"$in": [2014, 2015]
}
}
]
} Оператор $or
Оператор $or находит совпадение, если совпадает любой селектор в массиве. Ниже приведён пример с индексом по полю "year":
{
"year": 1977,
"$or": [
{ "director": "George Lucas" },
{ "director": "Steven Spielberg" }
]
} Оператор $not
Оператор $not находит совпадение, если заданный селектор не совпадает. Ниже приведён пример с индексом по полю "year":
{
"year": {
"$gte": 1900,
"$lte": 1903
},
"$not": {
"year": 1901
}
} Оператор $nor
Оператор $nor находит совпадение, если заданный селектор не совпадает. Ниже приведён пример с индексом по полю "year":
{
"year": {
"$gte": 1900.
"$lte": 1910
},
"$nor": [
{ "year": 1901 },
{ "year": 1905 },
{ "year": 1907 }
]
} Оператор $all
Оператор $all находит совпадение со значением-массивом, если оно содержит все элементы массива-аргумента. Ниже приведён пример с использованием первичного индекса (_all_docs):
{
"_id": {
"$gt": null
},
"genre": {
"$all": ["Comedy","Short"]
}
} Оператор $elemMatch
Оператор $elemMatch находит и возвращает все документы, содержащие поле-массив хотя бы с одним элементом, соответствующим заданным критериям запроса. Ниже приведён пример с использованием первичного индекса (_all_docs):
{
"_id": { "$gt": null },
"genre": {
"$elemMatch": {
"$eq": "Horror"
}
}
} Оператор $allMatch
Оператор $allMatch находит и возвращает все документы, содержащие поле-массив, все элементы которого соответствуют заданным критериям запроса. Ниже приведён пример с использованием первичного индекса (_all_docs):
{
"_id": { "$gt": null },
"genre": {
"$allMatch": {
"$eq": "Horror"
}
}
} Оператор $keyMapMatch
Оператор $keyMapMatch находит и возвращает все документы, содержащие карту хотя бы с одним ключом, соответствующим всем заданным критериям запроса. Ниже приведён пример с использованием первичного индекса (_all_docs):
{
"_id": { "$gt": null },
"cameras": {
"$keyMapMatch": {
"$eq": "secondary"
}
}
} Оператор $text
Оператор $text выполняет полнотекстовый поиск с использованием индекса Search или Nouveau. Детали запроса соответствуют либо синтаксису Search, либо синтаксису Nouveau (оба используют Lucene и реализуют один и тот же синтаксис).
{
"_id": { "$gt": null },
"$text": "director:George"
} Предупреждение
Запросы не могут содержать более одного $text
Операторы условий
Операторы условий относятся к конкретному полю и используются для проверки значения, хранящегося в этом поле. Например, базовый оператор $eq находит совпадение, когда указанное поле содержит значение, равное переданному аргументу.
Примечание
Чтобы оператор условия работал правильно, поле должно существовать в документе, иначе селектор не найдёт совпадение. Например, $ne означает, что указанное поле должно существовать и не должно быть равно значению аргумента.
Поддерживаются базовые операторы равенства и неравенства, распространённые в большинстве языков программирования. Используется строгое сопоставление типов.
Кроме того, доступны некоторые «мета»-операторы условий. Некоторые операторы условий принимают в качестве аргумента любое допустимое содержимое JSON. Для других операторов условий требуется аргумент в определённом формате JSON.
Тип оператора | Оператор | Аргумент | Назначение |
|---|---|---|---|
(Не)равенство |
| Любое значение JSON | Поле меньше аргумента. |
| Любое значение JSON | Поле меньше аргумента или равно ему. | |
| Любое значение JSON | Поле равно аргументу. | |
| Любое значение JSON | Поле не равно аргументу. | |
| Любое значение JSON | Поле больше аргумента или равно ему. | |
| Любое значение JSON | Поле больше аргумента. | |
Объект |
| Логическое значение | Проверяет, существует ли поле, независимо от его значения. |
| Строка | Проверяет тип поля документа. Допустимые значения: | |
Массив |
| Массив значений JSON | Поле документа должно присутствовать в указанном списке. |
| Массив значений JSON | Поле документа не должно присутствовать в указанном списке. | |
| Целое число | Специальное условие для проверки длины поля-массива в документе. Поля, не являющиеся массивами, не могут соответствовать этому условию. | |
Прочее |
| [Делитель, Остаток] | Делитель — ненулевое целое число, остаток — любое целое число. Значения, не являющиеся целыми числами, приводят к ошибке 404. Находит документы, для которых |
| Строка | Шаблон регулярного выражения для сопоставления с полем документа. Совпадение возможно только в том случае, если поле содержит строковое значение, соответствующее заданному регулярному выражению. Алгоритмы сопоставления основаны на библиотеке регулярных выражений Perl Compatible Regular Expression (PCRE). Дополнительную информацию о реализованных возможностях см. в разделе регулярных выражений Erlang. | |
| Строка | Находит документы, поле которых начинается с указанного префикса (с учётом регистра). Если поле документа содержит значение не строкового типа, документ не будет найден. |
Предупреждение
Регулярные выражения не работают с индексами, поэтому их не следует использовать для фильтрации больших наборов данных. Однако их можно использовать для ограничения частичного индекса.
Создание выражений селекторов
Мы уже рассматривали примеры объединения выражений селекторов, например использование явных операторов $and и $eq.
Как правило, если оператор принимает аргумент, этим аргументом может быть другой оператор с собственными аргументами. Это позволяет создавать более сложные выражения селекторов.
Однако только операторы, задающие непрерывный диапазон значений, такие как $eq, $gt, $gte, $lt, $lte и $beginsWith (но не $ne), могут служить основой для запроса, эффективно использующего индекс json. Следует включить в селектор хотя бы один из этих операторов или рассмотреть возможность использования индекса text, если требуется большая гибкость.
Например, если попытаться выполнить запрос для поиска всех документов, в которых поле afieldname содержит значение, начинающееся с буквы A, появится предупреждение, поскольку индекс использовать невозможно и база данных выполняет полное сканирование первичного индекса:
Запрос
POST /movies/_find HTTP/1.1 Accept: application/json Content-Type: application/json Content-Length: 112 Host: localhost:5984 { "selector": { "afieldname": {"$regex": "^A"} } }Ответ:
HTTP/1.1 200 OK Cache-Control: must-revalidate Content-Type: application/json Date: Thu, 01 Sep 2016 17:25:51 GMT Server: CouchDB (Erlang OTP) Transfer-Encoding: chunked { "warning":"no matching index found, create an index to optimize query time", "docs":[ ] }
Предупреждение
При развертывании в рабочей среде всегда рекомендуется создавать подходящий индекс.
Большинство выражений селекторов работают именно так, как можно ожидать от соответствующего оператора. Однако это не всегда так: например, сравнение строк выполняется с помощью ICU и может давать неожиданные результаты, если вы ожидали сортировку ASCII. Дополнительные сведения см. в разделе Сортировка в представлениях.
Индексы
Индексы похожи на индексы в большинстве других систем баз данных: они занимают немного дополнительного места, повышая производительность запросов.
В основном они состоят из списка индексируемых полей, но также могут содержать селектор для создания частичного индекса.
Примечание
Индексы Mango имеют тип: json, text, nouveau. В большей части этого документа рассматриваются индексы json. text и nouveau связаны соответственно с системами Search и Nouveau. (См. раздел Текстовые индексы.)
Также иногда встречается упоминание типа индекса special. Так обозначаются синтетические индексы, создаваемые самой CouchDB; это название относится исключительно к _all_docs.
Определения индексов
Определения индексов представляют собой объекты JSON со следующими полями:
ddoc (string): идентификатор документа дизайна, которому принадлежит индекс. По этому идентификатору можно получить документ дизайна с индексом, отправив запрос
GETк/{db}/ddoc, гдеddoc— значение этого поля.name (string): имя индекса.
partitioned (boolean): секционированный (
true) или глобальный (false) индекс.type (string): тип индекса. Может иметь значение
"json","text","nouveau"или иногда"special".def/index (object): определение индекса, зависящее от его типа (см. ниже). Используемое имя зависит от контекста.
Индексы JSON
Индексы JSON — это стандартные структурные индексы, используемые большинством операторов селекторов.
Их определение состоит из следующих элементов:
fields (array): массив имён полей в соответствии с синтаксисом сортировки. Также допускаются вложенные поля, например “person.name”.
partial_filter_selector (object): селектор, применяемый к документам во время индексирования для создания частичного индекса. Необязательный параметр
Пример:
{
"type" : "json",
"index": {
"fields": ["foo"]
}
} Частичные индексы
Частичные индексы позволяют фильтровать документы во время индексирования, что может значительно повысить производительность селекторов запросов, которые невозможно напрямую сопоставить с диапазоном значений в индексе.
Рассмотрим пример запроса:
{
"selector": {
"status": {
"$ne": "archived"
},
"type": "user"
}
} Без частичного индекса потребуется полностью просканировать индекс, чтобы найти все документы типа "type":"user", у которых статус не равен "archived". Это связано с тем, что обычный индекс можно использовать только для поиска в непрерывных строках, а оператор "$ne" этого не гарантирует.
Чтобы ускорить обработку запросов, можно создать индекс, исключающий документы, для которых "status": { "$ne": "archived" }, во время индексирования с помощью поля "partial_filter_selector":
POST /db/_index HTTP/1.1
Content-Type: application/json
Content-Length: 144
Host: localhost:5984
{
"index": {
"partial_filter_selector": {
"status": {
"$ne": "archived"
}
},
"fields": ["type"]
},
"ddoc" : "type-not-archived",
"type" : "json"
} В настоящее время планировщик запросов не использует частичные индексы, если они не указаны в поле "use_index", поэтому необходимо изменить исходный запрос:
{
"selector": {
"status": {
"$ne": "archived"
},
"type": "user"
},
"use_index": "type-not-archived"
} Технически фильтр по полю "status" необязательно включать в селектор запроса — частичный индекс гарантирует, что это условие всегда выполняется. Однако его включение делает назначение селектора яснее и упрощает использование будущих улучшений планирования запросов (например, автоматического выбора частичных индексов).
Примечание
Индекс с полями используется только в том случае, если селектор включает все индексируемые поля. Например, если индекс содержит ["a", "b"], а селектор требует только существования поля ["a"] в подходящих документах, такой индекс нельзя использовать для запроса. Однако все индексы можно считать содержащими специальные поля _id и _rev. Их никогда не нужно указывать в селекторе запроса.
Текстовые индексы
Mango также может взаимодействовать с поисковыми системами Search и Nouveau с помощью селектора $text и соответствующего индекса. Запросы к этим индексам можно выполнять с помощью $text или GET /{db}/_design/{ddoc}/_search/{index} / GET /{db}/_design/{ddoc}/_nouveau/{index}.
Пример индекса:
{
"type": "nouveau",
"index": {
"fields": [
{"name": "foo", "type": "string"},
{"name": "bar", "type": "number"},
{"name": "baz", "type": "string"},
],
"default_analyzer": "keyword",
}
} Определение индекса Text или Nouveau состоит из следующих элементов:
-
fields: список индексируемых полей.
"all_fields"или список объектов:name (string): не должен быть пустым
type (string): одно из значений
"text","string","number","boolean"
default_analyzer (string): используемый анализатор; по умолчанию
"keyword". Необязательный параметрdefault_field: включает индекс «поля по умолчанию»; логическое значение или объект из
enabledиanalyzer. Необязательный параметрpartial_filter_selector (object): селектор, превращающий индекс в частичный индекс. Необязательный параметр
selector (object): селектор. Необязательный параметр
Индексы и документы дизайна
В конечном счёте индексы хранятся с помощью документов дизайна и используют те же системы представлений на нижнем уровне. При желании можно найти документы дизайна, лежащие в основе индексов Mango. Однако точное соответствие индексов Mango документам дизайна является деталью реализации; пользователям рекомендуется управлять индексами с помощью семейства конечных точек /{db}/_index.
Copyright © 2025 The Apache Software Foundation — Licensed under the Apache License 2.0
https://docs.couchdb.org/en/3.5.1/ddocs/mango.html