mongodb нечувствительный к регистру поиск без использования регулярного выражения [duplicate]

С C # 4.0 отражение не требуется, поскольку DLR может вызывать его с использованием типов времени выполнения. Так как использование библиотеки DLR представляет собой боль динамически (вместо кода генерации компилятора C # для вас), open source framework Dynamitey (.net standard 1.5) дает вам простой кэшированный доступ во время выполнения те же вызовы, которые генерирует компилятор для вас.

var name = InvokeMemberName.Create;
Dynamic.InvokeMemberAction(this, name("GenericMethod", new[]{myType}));


var staticContext = InvokeContext.CreateStatic;
Dynamic.InvokeMemberAction(staticContext(typeof(Sample)), name("StaticMethod", new[]{myType}));

239
задан John Saunders 8 December 2009 в 06:18
поделиться

22 ответа

Вы можете использовать regex .

В вашем примере это будет:

db.stuff.find( { foo: /^bar$/i } );

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

255
ответ дан rfunduk 19 August 2018 в 11:04
поделиться
  • 1
    Это прекрасно работает. Получил его работу в PHP с помощью: $ collection- & gt; find (array ('key' = & gt; new MongoRegex ('/' .$ val. '/ I'))); – Luke Dennis 9 December 2009 в 05:22
  • 2
    Особенно, если вы интерполируете строку ({foo: / # {x} / i}), которая может содержать знак вопроса. – Peter Ehrlich 16 December 2011 в 20:53
  • 3
    Не забывайте также ^ и $: MongoRegex ('/ ^'. Preg_quote ($ val). '$ / I') – Julien 1 January 2013 в 22:26
  • 4
    Обратите внимание, что это будет делать fullscan вместо использования индекса. – Martin Konicek 25 April 2013 в 14:29
  • 5
    он не будет делать fullscan, если он использует якорь в начале, следовательно, важность совета Жюльена. – Pax 6 July 2013 в 23:37

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

9
ответ дан Aidan Feldman 19 August 2018 в 11:04
поделиться
  • 1
    Чтобы прояснить это: нечувствительные к регистру поисковые запросы разрешены в индексированных полях, они просто не будут использовать индекс и будут такими же медленными, как если бы поле не индексировалось. – heavi5ide 19 December 2011 в 19:22
  • 2
    @ heavyi5ide, так как этот вопрос используется для отметки дубликатов, я думал, что уточню, что регулярные выражения (необходимые для нечувствительных к регистру поиска) используют индекс, однако они должны выполнять полное сканирование индекса. Другими словами, они не могут эффективно использовать индекс. К счастью, с тех пор документация была обновлена ​​с 2011 года, но все еще хорошо здесь. – Sammaye 13 August 2014 в 18:37

Предположим, что вы хотите найти «столбец» в «Таблице», и вы хотите, чтобы поиск в insensstive. Лучший и эффективный способ: ниже

//create empty JSON Object
mycolumn = {};

//check if column has valid value
if(column) {
    mycolumn.column = {$regex: new RegExp(column), $options: "i"};
}
Table.find(mycolumn);

Выше кода просто добавляет ваше значение поиска как RegEx и выполняется поиск с критериями insensitve, установленными с опцией «i».

Все лучший.

5
ответ дан Ankur Soni 19 August 2018 в 11:04
поделиться

Они были протестированы для поиска строк

{'_id': /.*CM.*/}               ||find _id where _id contains   ->CM
{'_id': /^CM/}                  ||find _id where _id starts     ->CM
{'_id': /CM$/}                  ||find _id where _id ends       ->CM

{'_id': /.*UcM075237.*/i}       ||find _id where _id contains   ->UcM075237, ignore upper/lower case
{'_id': /^UcM075237/i}          ||find _id where _id starts     ->UcM075237, ignore upper/lower case
{'_id': /UcM075237$/i}          ||find _id where _id ends       ->UcM075237, ignore upper/lower case
0
ответ дан Ar maj 19 August 2018 в 11:04
поделиться

Как вы можете видеть в документах mongo - поскольку индекс версии 3.2 $text по умолчанию не чувствителен к регистру: https://docs.mongodb.com/manual/core/index-text/#text-index -фаза-нечувствительность

Создайте текстовый индекс и используйте текстовый оператор в вашем запросе .

0
ответ дан avalanche1 19 August 2018 в 11:04
поделиться

Использование фильтра работает для меня в C #.

string s = "searchTerm";
    var filter = Builders<Model>.Filter.Where(p => p.Title.ToLower().Contains(s.ToLower()));
                var listSorted = collection.Find(filter).ToList();
                var list = collection.Find(filter).ToList();

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

Это также позволяет избежать проблемы

var filter = Builders<Model>.Filter.Eq(p => p.Title.ToLower(), s.ToLower());

, что mongodb будет думать, что p.Title.ToLower () является свойством и не будет правильно отображаться.

0
ответ дан A_Arnold 19 August 2018 в 11:04
поделиться

Используя Mongoose, это сработало для меня:

var find = function(username, next){
    User.find({'username': {$regex: new RegExp('^' + username, 'i')}}, function(err, res){
        if(err) throw err;
        next(null, res);
    });
}
7
ответ дан ChrisRich 19 August 2018 в 11:04
поделиться
  • 1
    Не является ли избыточным .toLowerCase(), если вы указываете флаг, нечувствительный к регистру i? – k00k 1 July 2015 в 15:01
  • 2
    Да. Вам не нужно .toLowerCase (). Я удалил его из ответа. – ChrisRich 18 May 2017 в 01:00
  • 3
    Хм, если это сработает? Когда я ищу «отметку», он также получает каждую запись с "marko" - Есть ли способ игнорировать чувствительность к регистру? – Suisse 19 June 2017 в 00:54
  • 4
    Хорошо нашел это, правильное регулярное выражение будет: '^' + serach_name + '$', & quot; i & quot; – Suisse 19 June 2017 в 01:02
  • 5
    Это ОПАСНО. Вы не избегаете имени пользователя, поэтому любое произвольное регулярное выражение может быть введено. – Tom Mettam 17 January 2018 в 01:37

Одна важная вещь, которую следует иметь в виду при использовании запроса на основе Regex. Когда вы делаете это для системы входа в систему, удаляет каждый отдельный символ , который вы ищете, и не забывайте ^ и $ операторов. Lodash имеет приятную функцию для этого , если вы уже используете его:

db.stuff.find({$regex: new RegExp(_.escapeRegExp(bar), $options: 'i'})

Почему? Представьте, что пользователь вводит .* в качестве своего имени пользователя. Это будет соответствовать всем именам пользователей, что позволит войти в систему, просто угадывая пароль пользователя.

53
ответ дан Community 19 August 2018 в 11:04
поделиться
  • 1
    new RegExp("^" + req.params.term.toLowerCase(), "i") также отлично работает – Tahir Yasin 29 March 2017 в 15:43
  • 2
    вам следует рассмотреть возможность экранирования строки для повышения безопасности, если переменная поступает из запроса: stackoverflow.com/a/50633536/5195127 – davidivad 31 May 2018 в 22:19

Для поиска переменной и ее экранирования:

const escapeStringRegexp = require('escape-string-regexp')
const name = 'foo'
db.stuff.find({name: new RegExp('^' + escapeStringRegexp(name) + '$', 'i')})   

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

escape-string-regexp

1
ответ дан davidivad 19 August 2018 в 11:04
поделиться

Использовать RegExp. Если какие-либо другие параметры не работают для вас, RegExp является хорошим вариантом. Это делает строковый регистр чувствительным.

var username = "John";

var uname = new RegExp(username, "i");

Значение uname будет похоже на /John/i.

использовать uname в запросах вместо имени пользователя, а затем его выполнить.

Надеюсь, это сработает и для вас. Все лучшее.

0
ответ дан Dev911 19 August 2018 в 11:04
поделиться

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

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

/* strength: CollationStrength.Secondary
* Secondary level of comparison. Collation performs comparisons up to secondary * differences, such as diacritics. That is, collation performs comparisons of 
* base characters (primary differences) and diacritics (secondary differences). * Differences between base characters takes precedence over secondary 
* differences.
*/
db.users.createIndex( { name: 1 }, collation: { locale: 'tr', strength: 2 } } )

Чтобы использовать индекс, запросы должны указывать одну и ту же сортировку.

db.users.insert( [ { name: "Oğuz" },
                            { name: "oğuz" },
                            { name: "OĞUZ" } ] )

// does not use index, finds one result
db.users.find( { name: "oğuz" } )

// uses the index, finds three results
db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 2 } )

// does not use the index, finds three results (different strength)
db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 1 } )

или вы можете создать коллекцию с сравнение по умолчанию:

db.createCollection("users", { collation: { locale: 'tr', strength: 2 } } )
db.users.createIndex( { name : 1 } ) // inherits the default collation
1
ответ дан Gencebay D. 19 August 2018 в 11:04
поделиться
  • 1
    Там, по-видимому, незначительная проблема синтаксиса (отсутствующие брекеты). Пожалуйста, обновите запрос: db.users.createIndex( { name: 1 }, {collation: { locale: 'tr', strength: 2 } } ) – Mohd Belal 12 April 2018 в 11:56

Имейте в виду, что предыдущий пример:

db.stuff.find( { foo: /bar/i } );

приведет к тому, что каждая запись, содержащая бар, будет соответствовать запросу (bar1, barxyz, openbar), это может быть очень опасно для поиска имени пользователя на auth function ...

Возможно, вам потребуется сопоставить только поисковый запрос, используя соответствующий синтаксис regexp как:

db.stuff.find( { foo: /^bar$/i } );

См. http: // www .regular-expressions.info / для синтаксической справки по регулярным выражениям

56
ответ дан jflaflamme 19 August 2018 в 11:04
поделиться

UPDATE:

Исходный ответ устарел. Mongodb теперь поддерживает расширенный полнотекстовый поиск со многими функциями.

ОРИГИНАЛЬНЫЙ ОТВЕТ:

Следует отметить, что поиск с регистрозависимым регистром нечувствителен / i означает, что mongodb не может искать по индексу, поэтому запросы к большим наборам данных могут занять много времени.

Даже с небольшими наборами данных это не очень эффективно. Вы делаете гораздо больший бит процессора, чем ваши ордера на запрос, что может стать проблемой, если вы пытаетесь достичь масштаба.

. В качестве альтернативы вы можете хранить заглавную копию и искать ее. Например, у меня есть таблица User, у которой есть имя пользователя, которое является смешанным случаем, но идентификатор является заглавной копией имени пользователя. Это гарантирует, что дублирование, чувствительное к регистру, невозможно (иметь возможность «Foo» и «foo» не будет разрешено), и я могу выполнить поиск по id = username.toUpperCase (), чтобы получить поиск по имени пользователя без регистра.

Если ваше поле большое, например тело сообщения, дублирование данных, вероятно, не является хорошим вариантом. Я считаю, что использование альтернативного индексатора, такого как Apache Lucene, является лучшим вариантом в этом случае.

189
ответ дан Jhuliano Moreno 19 August 2018 в 11:04
поделиться
  • 1
    Доступна ли какая-либо документация, показывающая, как работают индексы? Я спрашиваю, потому что, если я помню, marklogic может содержать дополнительный регистр, нечувствительный к регистру ... может, монго делает то же самое? – RayLoveless 31 December 2012 в 19:05
  • 2
    Раймо, особенность индекса, нечувствительная к регистру, не существует сегодня в Монго, но об этом говорят. jira.mongodb.org/browse/SERVER-90 – Dan 19 February 2013 в 05:18
  • 3
    FYI, мой ответ теперь устарел. Mongodb теперь поддерживает расширенный полнотекстовый поиск со многими функциями. См. docs.mongodb.org/manual/core/index-text – Dan 11 August 2014 в 21:02
  • 4
    @Dan, только для информации в последнем MongoDB, & quot; Если индекс существует для этого поля, то MongoDB сопоставляет регулярное выражение со значениями в индексе, которое может быть быстрее, чем сканирование коллекции. & Quot; - docs.mongodb.org/manual/reference/operator/query/regex/… – Sergiy Sokolenko 16 November 2015 в 14:28
  • 5
    @Dan, следует отметить, что новый полнотекстовый индекс имеет свои проблемы - «Для латинского алфавита текстовые индексы нечувствительны к регистру для не диакритики; т.е. нечувствительность к регистру для [A-z]. Для всех других символов текстовые индексы рассматривают их как разные. & Quot ;; Таким образом, для не латинского алфавита может быть разумным использовать поиск в регулярном выражении, который также должен воспользоваться преимуществом существующего индекса (см. Мой комментарий выше). – Sergiy Sokolenko 16 November 2015 в 14:32

Структура агрегирования была введена в mongodb 2.2. Вы можете использовать строковый оператор «$ strcasecmp», чтобы сделать нечувствительное к регистру сравнение строк. Это более рекомендуется и проще, чем при использовании регулярного выражения.

Вот официальный документ оператора оператора агрегации: https://docs.mongodb.com/manual/reference/operator/aggregation/strcasecmp/# exp._S_strcasecmp .

3
ответ дан Jogue Wasin 19 August 2018 в 11:04
поделиться
  • 1
    как использовать это в запросе find ()? db.stuff.find ({name: $ strcasecmp (name)})? – Suisse 19 June 2017 в 00:51
db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive
db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity
16
ответ дан Maneating Koala 19 August 2018 в 11:04
поделиться
  • 1
    Пожалуйста, добавьте описание в код. – Parth Trivedi 17 December 2015 в 14:02
  • 2
    @ParthTrivedi, комментарии примерно до тех пор, пока сам код. Вы хотите 3-х эссе или что-то еще? – Oleg V. Volkov 17 December 2015 в 15:22
  • 3
    @ OlegV.Volkov должен иметь описание о том, как ваш ответ подходит и что не так в вопросительном коде. – Parth Trivedi 18 December 2015 в 05:39

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

private Func<string, BsonRegularExpression> CaseInsensitiveCompare = (field) => 
            BsonRegularExpression.Create(new Regex(field, RegexOptions.IgnoreCase));

Затем вы просто фильтруете поле в следующем виде.

db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();
0
ответ дан Nitesh 19 August 2018 в 11:04
поделиться

Лучший способ заключается в выборе вашего языка при создании обертки модели для ваших объектов, попробуйте выполнить метод save () через набор полей, которые вы будете искать, которые также индексируются; эти группы полей должны иметь строчные копии, которые затем используются для поиска.

Каждый раз, когда объект сохраняется снова, нижние значения затем проверяются и обновляются с любыми изменениями основных свойств. Это сделает так, чтобы вы могли эффективно искать, но скрыть дополнительную работу, необходимую для обновления полей lc каждый раз.

В нижнем регистре могут быть хранилище объектов с ключом: значение или просто имя поля с префикс lc_. Я использую второй, чтобы упростить запрос (запросы на глубинные объекты могут иногда заблуждаться).

Примечание: вы хотите индексировать поля lc_, а не основные поля, на которых они основаны.

5
ответ дан RobKohr 19 August 2018 в 11:04
поделиться

В соответствии с Mongodb 3.4 вы должны использовать индекс индексирования без учета регистра. Это самый быстрый способ сделать поиск без учета регистра данных по наборам данных большего размера. Я лично отправил по электронной почте одного из основателей, чтобы получить эту работу, и он сделал это! (Это была проблема JIRA как 5 лет, и многие просили эту функцию). Вот как это работает:

Индекс чувствительности к регистру производится путем задания сопоставления с силой 1 или 2. Вы можете создать индекс без учета регистра следующим образом:

db.myCollection.createIndex({city: 1}, {collation: {locale: "en", strength: 2}});

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

db.createCollection("Cities",{collation: {locale: "en",strength:2}});

И использовать ее следующим образом:

db.myCollection.find({city: "new york"}).collation({locale: "en", strength: 2});

Это будет return "New York", "new york" и т. д.

В качестве альтернативы вы можете сделать все индексы по умолчанию, когда вы создаете такую ​​коллекцию:

db.createCollection("cities",{collation:{locale: "en", strength: 2}});

Преимущество этого метода - значительно повысить эффективность и скорость работы с большими наборами данных.

Для получения дополнительной информации: https://jira.mongodb.org/browse/SERVER-90 , https://docs.mongodb.com/manual/reference/collation/

18
ответ дан user3413723 19 August 2018 в 11:04
поделиться

TL; DR

Правильный способ сделать это в mongo

Не использовать RegExp

Перейти к естественному и использовать встроенное индексирование mongodb, поиск

Шаг 1:

db.articles.insert(
   [
     { _id: 1, subject: "coffee", author: "xyz", views: 50 },
     { _id: 2, subject: "Coffee Shopping", author: "efg", views: 5 },
     { _id: 3, subject: "Baking a cake", author: "abc", views: 90  },
     { _id: 4, subject: "baking", author: "xyz", views: 100 },
     { _id: 5, subject: "Café Con Leche", author: "abc", views: 200 },
     { _id: 6, subject: "Сырники", author: "jkl", views: 80 },
     { _id: 7, subject: "coffee and cream", author: "efg", views: 10 },
     { _id: 8, subject: "Cafe con Leche", author: "xyz", views: 10 }
   ]
)

Шаг 2:

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

db.articles.createIndex( { subject: "text" } )

шаг 3:

db.articles.find( { $text: { $search: "coffee",$caseSensitive :true } } )  //FOR SENSITIVITY
db.articles.find( { $text: { $search: "coffee",$caseSensitive :false } } ) //FOR INSENSITIVITY
11
ответ дан vijay 19 August 2018 в 11:04
поделиться
  • 1
    Хороший вариант, но нет ничего более «правильного». об использовании текстового индекса по сравнению с регулярным выражением, это просто еще один вариант. Это излишний случай для OP. – JohnnyHK 28 August 2016 в 02:16
  • 2
    За исключением регулярного выражения значительно медленнее. Полнотекстовый поиск также медленный, но не такой медленный. Самый быстрый (но более раздутый) способ - это отдельное поле, которое всегда задано в нижнем регистре. – Tom Mettam 17 January 2018 в 01:37

Я столкнулся с подобной проблемой, и это сработало для меня:

  const flavorExists = await Flavors.findOne({
    'flavor.name': { $regex: flavorName, $options: 'i' },
  });
0
ответ дан Woppi 19 August 2018 в 11:04
поделиться
54
ответ дан Community 30 October 2018 в 23:25
поделиться
2
ответ дан Nilesh 30 October 2018 в 23:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: