Перевірка, чи містить поле рядок


454

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

Щось на зразок:

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

Це можливо?

Відповіді:


693

Ви можете зробити це за допомогою наступного коду.

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

16
Зауважте, що це не дозволить ефективно використовувати індекс і призведе до сканування всіх значень на відповідність. Дивіться примітки до регулярних виразів
Stennie

7
@Stennie, то що ви пропонуєте ефективно використовувати індекс і знайти підрядку.
Синє небо

4
@Vish: якщо вашим загальним випадком використання є пошук текстового поля у вільному тексті, і у вас є велика кількість документів, я б хотів подати текст для більш ефективних запитів. Ви можете використовувати кілька клавіш для простого повнотекстового пошуку або, можливо, побудувати перевернутий індекс як окрему колекцію. Для нечастого пошуку або невеликої колекції документів сканування повного індексу може бути прийнятною (хоча і не оптимальною) роботою.
Стенні

98
Хіба це не трохи зайвої? Те, що ти хочеш db.users.findOne({"username" : {$regex : "son"}});
JamieJag

3
Ви можете перевірити повний пошук тексту в Монго 2.6
впр

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
Видалити весь запит чи змінити його? найпопулярніший poeple з SQL, він корисний для розуміння MongoDB
Чжен Кай

4
@ZhengKai: на цьому веб-сайті, як правило, слід відповісти прямо на це питання, використовуючи лише конкретні технології, позначені тегами та запитами.
maerics

98
@maerics особисто я вважав, що включення Чженгом до MySQL було дуже корисним, оскільки воно надало точку заперечення.
Майк Бартлетт

50
Я також знайшов посилання на SQL релевантним, я думаю, він повинен залишатися.
vikingsteve

69

Починаючи з версії 2.4, ви можете створити текстовий покажчик у полях (полях) для пошуку та використання $ текстового оператора для запитів.

Спочатку створіть індекс:

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

Потім для пошуку:

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

Орієнтовні показники (~ 150 000 документів):

  • Регекс (інші відповіді) => 5,6-6,9 секунди
  • Пошук тексту => .164-.201 секунд

Примітки:

  • Колекція може мати лише один текстовий покажчик. Ви можете використовувати підстановлювальний індекс тексту , якщо ви хочете знайти будь- строкове поле, як це: db.collection.createIndex( { "$**": "text" } ).
  • Текстовий покажчик може бути великим. Він містить один запис індексу для кожного унікального післястебельного слова у кожному індексованому полі для кожного вставленого документа.
  • Текстовий індекс буде тривати довше, ніж звичайний індекс.
  • Текстовий покажчик не зберігає у документах фрази чи інформацію про близькість слів. В результаті фразові запити будуть працювати набагато ефективніше, коли вся колекція вписується в оперативну пам’ять.

14
ні, текстовий оператор Infact не дозволяє виконати "містити", тому він поверне лише точну відповідність слова, єдиний на даний момент варіант 3.0 - це використовувати regex, тобто db.users.find ({ім'я користувача: / son / i} ) цей шукає кожного користувача, що містить "son" (case-insnstive)
comeGetSome

3
Чи доводиться повторно встановлювати, коли ви додаєте або видаляєте документи до колекції?
Джейк Вілсон

У заголовку питання написано "містить". повний пошук тексту не стосується питання.
Донато

29

Оскільки це одне з перших звернень у пошукових системах, і жодне з перерахованих вище, здається, не працює для MongoDB 3.x, ось один пошук регулярного вибору, який працює:

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

Не потрібно створювати і додатково індексувати або подібні.


1
Регекси потрібно санітувати.
sean

16

Ось що вам потрібно зробити, якщо ви підключаєте MongoDB через Python

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

Ви також можете використовувати ім'я змінної замість "Son", а отже, і з'єднання рядків.


в es2015 ви можете використовувати зворотні посилання {$ regex: .*${value}.*}
Гільдія Майкла

16

Найпростіший спосіб виконання цього завдання

Якщо ви хочете, щоб запит залежав від регістру

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

Якщо ви хочете, щоб запит не залежно від регістру

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

1
як використовувати змінну з регулярним виразом ??
Хішам

4

ідеальна відповідь на його індекс використання i варіант для нечутливих до регістру

db.users.findOne({"username" : new RegExp(search_value, 'i') });

Регекси потрібно санітувати.
sean


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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.