Проверка, содержит ли поле строку

454

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

Что-то вроде:

db.users.findOne({$contains:{"username":"son"}})

Это возможно?

Джонни
источник

Ответы:

693

Вы можете сделать это с помощью следующего кода.

db.users.findOne({"username" : {$regex : ".*son.*"}});
Парвин Гасымзаде
источник
16
Обратите внимание, что это не будет эффективно использовать индекс и приведет к тому, что все значения будут проверяться на совпадения. См. Примечания к регулярным выражениям
Стенни
7
@ Стенни, тогда что вы предлагаете для эффективного использования индекса и поиска подстроки.
Голубое небо
4
@Vish: если вы обычно используете произвольный текстовый поиск поля и у вас есть большое количество документов, я бы разбил текст на части для более эффективных запросов. Вы можете использовать многопользовательские клавиши для простого полнотекстового поиска или, возможно, создать инвертированный индекс как отдельную коллекцию. Для нечастых поисков или небольшой коллекции документов сканирование полного индекса может быть приемлемой (хотя и не оптимальной) производительностью.
Стенни
98
Разве это не излишество? То, что вы хотите, db.users.findOne({"username" : {$regex : "son"}});
JamieJag
3
Возможно, стоит
179

Поскольку оболочка Mongo поддерживает регулярные выражения, это вполне возможно.

db.users.findOne({"username" : /.*son.*/});

Если мы хотим, чтобы в запросе не учитывался регистр, мы можем использовать опцию «i», как показано ниже:

db.users.findOne({"username" : /.*son.*/i});

Смотрите: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-RegularExpressions

Джеймс Ган
источник
1
Пожалуйста, включите фрагмент кода, демонстрирующий использование регулярных выражений для поиска. Ответы должны включать больше информации, чем просто ссылка ...
maerics
1
Выбранный ответ не сработал для меня, но этот сработал (я выполняю монго-запросы с помощью команд docker exec). Я думаю, что этот ответ должен быть выбранным, потому что он выглядит более универсальным.
Артур Веборг
5
как и комментарии в выбранном ответе, я считаю, db.users.findOne({"username" : /.*son.*/});что это также может быть излишним, а регулярное выражение может быть простым/son/
Артур Веборг
2
Более краткий способ, чем использование $ regex
Lionet Chen
4
Отредактируйте это, чтобы просто использовать{ username: /son/ }
Wyck
150

https://docs.mongodb.com/manual/reference/sql-comparison/

http://php.net/manual/en/mongo.sqltomongo.php

MySQL

SELECT * FROM users WHERE username LIKE "%Son%"

MongoDB

db.users.find({username:/Son/})
Чжэн Кай
источник
8
Ваш ответ MongoDB хорош; рассмотрите возможность редактирования вашего вопроса, чтобы удалить ненужный совет MySQL.
maerics
31
Удалить весь запрос или изменить его? наиболее известный SQL, это полезно для понимания MongoDB
Чжэн Кай
4
@ZhengKai: на этом сайте вы, как правило, должны отвечать на этот вопрос напрямую, используя только специальные технологии, помеченные и запрошенные.
maerics
98
@maerics лично Я считаю, что включение Чжэн в MySQL очень полезно, поскольку оно дает точку отсчета.
Майк Бартлетт
50
Я также нашел ссылку на SQL актуальной, я думаю, что она должна остаться.
Викингстеве
69

Начиная с версии 2.4, вы можете создавать текстовые индексы в полях для поиска и использовать оператор $ text для запросов.

Сначала создайте индекс:

db.users.createIndex( { "username": "text" } )

Затем для поиска:

db.users.find( { $text: { $search: "son" } } )

Тесты (~ 150 тыс. Документов):

  • Regex (другие ответы) => 5,6-6,9 секунд
  • Поиск текста => .164-.201 секунд

Ноты:

  • Коллекция может иметь только один текстовый индекс. Вы можете использовать подстановочный индекс текста , если вы хотите найти любое строковое поле, как это: db.collection.createIndex( { "$**": "text" } ).
  • Текстовый индекс может быть большим. Он содержит одну запись указателя для каждого уникального слова после каждого элемента в каждом проиндексированном поле для каждого вставленного документа.
  • Для создания текстового индекса потребуется больше времени, чем для обычного индекса.
  • Текстовый указатель не хранит фразы или информацию о близости слов в документах. В результате запросы фраз будут выполняться намного эффективнее, когда вся коллекция помещается в ОЗУ.
okoboko
источник
14
нет, оператор текстового ввода не позволяет выполнять «содержит», поэтому он будет возвращать только точное совпадение слов. Начиная с версии 3.0 единственной возможностью в настоящее время является использование регулярного выражения, то есть db.users.find ({имя пользователя: / son / i} ) этот ищет каждого пользователя, содержащего «сын» (без учета регистра)
comeGetSome
3
Нужно ли переиндексировать при добавлении или удалении документов в / из коллекции?
Джейк Уилсон,
Название вопроса говорит «содержит». полнотекстовый поиск не применим к вопросу.
Донато
29

Так как это один из первых попаданий в поисковых системах, и ни один из вышеперечисленных, похоже, не работает для MongoDB 3.x, вот один поиск по регулярному выражению, который работает:

db.users.find( { 'name' : { '$regex' : yourvalue, '$options' : 'i' } } )

Не нужно создавать и дополнительный индекс или тому подобное.

Нитай
источник
1
Регулярные выражения должны быть очищены.
Шон
16

Вот что вам нужно сделать, если вы подключаете MongoDB через Python

db.users.find({"username": {'$regex' : '.*' + 'Son' + '.*'}})

Вы также можете использовать имя переменной вместо 'Son' и, следовательно, конкатенацию строк.

Patthebug
источник
в es2015 вы можете использовать обратные ссылки {$ regex: .*${value}.*}
Майкл Гильд
16

Самый простой способ выполнить эту задачу

Если вы хотите, чтобы в запросе учитывался регистр

db.getCollection("users").find({'username':/Son/})

Если вы хотите, чтобы в запросе не учитывался регистр

db.getCollection("users").find({'username':/Son/i})
Анураг Мисра
источник
1
как использовать переменную с регулярным выражением ??
Хишам
4

идеальный ответ его индекс использования я вариант для без учета регистра

db.users.findOne({"username" : new RegExp(search_value, 'i') });
Хишам
источник
Регулярные выражения должны быть очищены.
Шон
2

Это должно сделать работу

db.users.find({ username: { $in: [ /son/i ] } });

Это iпросто для того, чтобы не допустить ограничения совпадения отдельных букв.

Вы можете проверить документацию $ regex в документации MongoDB. Вот ссылка: https://docs.mongodb.com/manual/reference/operator/query/regex/

Тейт
источник
1

Как игнорировать теги HTML в совпадении с RegExp:

var text = '<p>The <b>tiger</b> (<i>Panthera tigris</i>) is the largest <a href="https://stackoverflow.com/wiki/Felidae" title="Felidae">cat</a> <a href="https://stackoverflow.com/wiki/Species" title="Species">species</a>, most recognizable for its pattern of dark vertical stripes on reddish-orange fur with a lighter underside. The species is classified in the genus <i><a href="https://stackoverflow.com/wiki/Panthera" title="Panthera">Panthera</a></i> with the <a href="https://stackoverflow.com/wiki/Lion" title="Lion">lion</a>, <a href="https://stackoverflow.com/wiki/Leopard" title="Leopard">leopard</a>, <a href="https://stackoverflow.com/wiki/Jaguar" title="Jaguar">jaguar</a>, and <a href="https://stackoverflow.com/wiki/Snow_leopard" title="Snow leopard">snow leopard</a>. It is an <a href="https://stackoverflow.com/wiki/Apex_predator" title="Apex predator">apex predator</a>, primarily preying on <a href="https://stackoverflow.com/wiki/Ungulate" title="Ungulate">ungulates</a> such as <a href="https://stackoverflow.com/wiki/Deer" title="Deer">deer</a> and <a href="https://stackoverflow.com/wiki/Bovid" class="mw-redirect" title="Bovid">bovids</a>.</p>';
var searchString = 'largest cat species';

var rx = '';
searchString.split(' ').forEach(e => {
  rx += '('+e+')((?:\\s*(?:<\/?\\w[^<>]*>)?\\s*)*)';
});

rx = new RegExp(rx, 'igm');

console.log(text.match(rx));

Это, вероятно, очень легко превратить в агрегирующий фильтр MongoDB.

Тамас Полгар
источник