Как выполнить запрос в MongoDB с использованием ‘like’
Я хочу выполнить запрос, аналогичный SQL-запросу like:
SELECT * FROM users WHERE name LIKE '%m%'
Как можно добиться того же самого в MongoDB? Я не могу найти оператор для ‘like’ в документации.
В MongoDB нет прямого оператора LIKE, как в SQL, но вы можете добиться той же функциональности с помощью оператора $regex. Для репликации запроса SELECT * FROM users WHERE name LIKE '%m%' вы бы использовали db.users.find({ name: { $regex: 'm' } }) или db.users.find({ name: { $regex: /m/ } }). Оператор $regex поддерживает регулярные выражения в стиле JavaScript для выполнения сопоставления шаблонов, аналогично оператору LIKE в SQL.
Содержание
- Базовое использование $regex
- Различные шаблоны LIKE в MongoDB
- Параметры чувствительности к регистру
- Рекомендации по производительности
- Практические примеры
- Альтернативные подходы
Базовое использование $regex
Основной способ достижения функциональности LIKE в MongoDB — это использование оператора $regex в сочетании с методом find(). Согласно официальной документации MongoDB, оператор $regex предоставляет “возможности регулярных выражений для сопоставления строк в запросах”.
Базовый синтаксис
// Найти документы, где поле содержит определенную подстроку
db.collection.find({ field: { $regex: 'pattern' } })
// Альтернативно с использованием объекта RegExp
db.collection.find({ field: { $regex: /pattern/ } })
Пример для конкретного запроса пользователя
Для SQL-запроса SELECT * FROM users WHERE name LIKE '%m%' эквивалент в MongoDB будет:
db.users.find({ name: { $regex: 'm' } })
// или
db.users.find({ name: { $regex: /m/ } })
Это найдет все документы, где поле name содержит букву “m” в любой части строки, так же как и шаблон SQL LIKE ‘%m%’.
Различные шаблоны LIKE в MongoDB
У шаблонов SQL LIKE есть разные символы-шаблоны, и каждый из них можно реплицировать в MongoDB с помощью шаблонов регулярных выражений:
Эквиваленты шаблонов SQL LIKE
| SQL LIKE Pattern | MongoDB $regex Equivalent | Описание |
|---|---|---|
LIKE '%pattern%' |
{$regex: 'pattern'} |
Шаблон появляется в любой части строки |
LIKE 'pattern%' |
{$regex: '^pattern'} |
Шаблон начинается со строки |
LIKE '%pattern' |
{$regex: 'pattern$'} |
Шаблон заканчивается строкой |
LIKE '_pattern' |
{$regex: '.pattern'} |
Шаблон начинается с любого одного символа |
LIKE 'a%b%c' |
{$regex: '^a.*b.*c$'} |
Сложный шаблон с несколькими шаблонами |
Практические примеры
// SQL: SELECT * FROM users WHERE name LIKE 'John%'
// MongoDB:
db.users.find({ name: { $regex: '^John' } })
// SQL: SELECT * FROM users WHERE name LIKE '%son'
// MongoDB:
db.users.find({ name: { $regex: 'son$' } })
// SQL: SELECT * FROM users WHERE name LIKE '%mit%'
// MongoDB:
db.users.find({ name: { $regex: 'mit' } })
// SQL: SELECT * FROM users WHERE name LIKE '_ohn'
// MongoDB:
db.users.find({ name: { $regex: '.ohn' } })
Как объясняется на Spark by Examples, “MongoDB не поддерживает оператор like SQL для запроса документа, однако вы можете использовать оператор $regex с методом db.collection.find() для получения аналогичного результата.”
Параметры чувствительности к регистру
Стандартное сопоставление с учетом регистра
По умолчанию, запросы регулярных выражений в MongoDB чувствительны к регистру:
db.users.find({ name: { $regex: 'john' } }) // Соответствует только "john", а не "John" или "JOHN"
Сопоставление без учета регистра
Для выполнения поиска без учета регистра используйте параметр $options с ‘i’:
db.users.find({
name: {
$regex: 'john',
$options: 'i'
}
})
// Соответствует: "john", "John", "JOHN", "jOhN" и т.д.
Согласно DataFlair, когда вы хотите найти все документы, в которых есть “ab” в поле Employee_name независимо от регистра, вы можете использовать параметр $options.
Расширенный контроль регистра
Вы также можете использовать встроенные модификаторы для более точного контроля:
// Чувствительность к регистру только для определенных частей
db.users.find({
name: {
$regex: '(?i)john(?-i)son'
}
})
// Соответствует "johnson" без учета регистра, но "son" с учетом регистра
Рекомендации по производительности
Использование индексов
MongoDB может эффективно использовать индексы с запросами регулярных выражений только при определенных условиях:
- Шаблон должен быть привязан к началу строки (начинается с
^) - Сопоставление должно быть чувствительным к регистру
- Отсутствие привязок или поиск без учета регистра означает, что запрос должен просканировать все документы
Как указано в документации MongoDB, “$regex может эффективно использовать индекс только тогда, когда регулярное выражение имеет привязку к началу (т.е. ^) строки и является чувствительным к регистру сопоставлением.”
Советы по оптимизации производительности
-
Используйте привязанные шаблоны для лучшей производительности:
javascript// Лучшая производительность - можно использовать индекс db.users.find({ name: { $regex: '^John' } }) // Плохая производительность - необходимо просканировать все документы db.users.find({ name: { $regex: 'John' } }) -
Избегайте поиска без учета регистра в больших коллекциях, когда это возможно
-
Рассмотрите текстовый поиск для сложного сопоставления шаблонов:
javascript// Сначала создайте текстовый индекс db.users.createIndex({ name: "text" }) // Используйте текстовый поиск db.users.find({ $text: { $search: "John" } })
Как отмечено в статье в блоге MongoDB, “Хотя эти подходы и прагматичны, в целом эффективны, они не показывают хорошей производительности в крупном масштабе.”
Практические примеры
Пример полного рабочего процесса
Давайте рассмотрим практический пример с разными сценариями LIKE:
// Пример данных
db.users.insertMany([
{ name: "John Doe", email: "john@example.com" },
{ name: "Alice Johnson", email: "alice@example.com" },
{ name: "Bob Smith", email: "bob@example.com" },
{ name: "Mary Wilson", email: "mary@example.com" },
{ name: "johnny walker", email: "johnny@example.com" }
])
// SQL: SELECT * FROM users WHERE name LIKE '%John%'
// MongoDB:
db.users.find({ name: { $regex: 'John' } })
// Результат: "John Doe", "Alice Johnson", "johnny walker"
// SQL: SELECT * FROM users WHERE name LIKE '%john%' (без учета регистра)
// MongoDB:
db.users.find({ name: { $regex: 'john', $options: 'i' } })
// Результат: "John Doe", "Alice Johnson", "johnny walker", "john@example.com"
// SQL: SELECT * FROM users WHERE name LIKE 'J%'
// MongoDB:
db.users.find({ name: { $regex: '^J' } })
// Результат: "John Doe"
// SQL: SELECT * FROM users WHERE name LIKE '%son'
// MongoDB:
db.users.find({ name: { $regex: 'son$' } })
// Результат: "Alice Johnson", "Bob Smith"
Пример с Node.js
Как показано в уроке на Morioh, вы также можете использовать объекты JavaScript RegExp:
const MongoClient = require('mongodb').MongoClient;
async function findUsersWithSubstring(searchTerm) {
const client = await MongoClient.connect('mongodb://localhost:27017');
const db = client.db('mydb');
const collection = db.collection('users');
// Поиск подстроки без учета регистра
const results = await collection.find({
name: new RegExp(searchTerm, 'i')
}).toArray();
console.log(results);
client.close();
}
// Использование
findUsersWithSubstring('john'); // Находит любое имя, содержащее 'john' без учета регистра
Альтернативные подходы
1. Использование $where для сложной логики
Для очень сложных операций, подобных LIKE, которые нельзя выразить с помощью регулярных выражений:
db.users.find({
$where: "this.name.indexOf('John') !== -1"
})
2. Конвейер агрегации с $substrCP
Для конкретных операций с подстроками:
db.users.aggregate([
{
$addFields: {
hasSubstring: {
$regexMatch: {
input: "$name",
regex: "John"
}
}
}
},
{
$match: { hasSubstring: true }
}
])
3. Текстовый поиск для полнотекстовых возможностей
Для более сложного текстового поиска:
// Сначала создайте текстовый индекс
db.users.createIndex({ name: "text", email: "text" })
// Используйте оператор $text
db.users.find({
$text: { $search: "John" }
})
Согласно уроку на Chartio, “Существует множество движков регулярных выражений, написанных с использованием немного различающегося синтаксиса, но основы во всех случаях в основном одинаковы, и в данном случае MongoDB использует движок Perl Regex (PCRE).”
Заключение
Для достижения функциональности SQL LIKE в MongoDB вам необходимо понять следующие ключевые моменты:
- Используйте оператор $regex как основной эквивалент SQL LIKE — это механизм сопоставления шаблонов MongoDB для строк
- Освойте шаблоны регулярных выражений:
patternдля%pattern%,^patternдляpattern%иpattern$для%pattern - Используйте параметр $options для поиска без учета регистра с опцией ‘i’
- Учитывайте последствия для производительности — привязанные шаблоны (
^pattern) работают лучше, так как могут использовать индексы - Изучите альтернативные подходы, такие как текстовый поиск, для сложных сценариев в больших наборах данных
Для вашего конкретного запроса SELECT * FROM users WHERE name LIKE '%m%' самый простой эквивалент в MongoDB — это db.users.find({ name: { $regex: 'm' } }). Если вам нужно сопоставление без учета регистра, используйте db.users.find({ name: { $regex: 'm', $options: 'i' } }).
Помните, что хотя регулярные выражения предоставляют мощные возможности сопоставления шаблонов, важно учитывать последствия для производительности, особенно при работе с большими наборами данных или сложными шаблонами.