MongoDB: Можно ли сделать запрос без учета регистра?

Пример:

> db.stuff.save({"foo":"bar"});

> db.stuff.find({"foo":"bar"}).count();
1
> db.stuff.find({"foo":"BAR"}).count();
0
вопрос задан 7.12.2009
Luke Dennis
6799 репутация

22 ответов


  • 262 рейтинг

    Вы можете использовать регулярное выражение .

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

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

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

    ответ дан rfunduk, с репутацией 25049, 7.12.2009
  • 189 рейтинг

    ОБНОВЛЕНИЕ:

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

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

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

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

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

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

    ответ дан Dan, с репутацией 2427, 14.12.2010
  • 57 рейтинг

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

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

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

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

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

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

    ответ дан jflaflamme, с репутацией 1563, 3.06.2011
  • 54 рейтинг

    Если вам нужно создать регулярное выражение из переменной, это гораздо лучший способ сделать это: https: // stackoverflow. com / a / 10728069/309514

    Затем вы можете сделать что-то вроде:

    var string = "SomeStringToFind";
    var regex = new RegExp(["^", string, "$"].join(""), "i");
    // Creates a regex of: /^SomeStringToFind$/i
    db.stuff.find( { foo: regex } );
    

    Это дает преимущество в том, что вы программируете больше, или вы можете получить повышение производительности, заблаговременно скомпилировав его, если будете многократно его использовать.

    ответ дан Fotios, с репутацией 2550, 12.07.2012
  • 19 рейтинг

    По состоянию на Монгодб 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});
    

    Это вернет "Нью-Йорк", "Нью-Йорк" и т. Д.

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

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

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

    Для получения дополнительной информации: https: // jira. MongoDB. org / browse / SERVER-90 , https: // docs. MongoDB. ru / руководство / справка / сопоставление /

    ответ дан user3413723, с репутацией 3519, 1.12.2016
  • 16 рейтинг
    db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive
    db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity
    
    ответ дан rshivamca, с репутацией 171, 17.12.2015
  • 11 рейтинг

    TL; DR

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

    Не использовать 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:

    Необходимо создать индекс для любого поля ТЕКСТ , которое вы хотите найти, без индексации запрос будет очень медленным

    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
    
    ответ дан vijay, с репутацией 3332, 27.08.2016
  • 9 рейтинг

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

    ответ дан Aidan Feldman, с репутацией 2515, 24.10.2011
  • 7 рейтинг

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

    var find = function(username, next){
        User.find({'username': {$regex: new RegExp('^' + username, 'i')}}, function(err, res){
            if(err) throw err;
            next(null, res);
        });
    }
    
    ответ дан ChrisRich, с репутацией 2274, 16.10.2014
  • 5 рейтинг

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

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

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

    ответ дан Ziao, с репутацией 51, 6.05.2016
  • 5 рейтинг

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

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

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

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

    ответ дан RobKohr, с репутацией 3280, 20.04.2011
  • 5 рейтинг

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

    //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 и выполняет поиск с нечувствительными критериями, установленными с параметром «i».

    Всего наилучшего.

    ответ дан Ankur Soni, с репутацией 2447, 30.04.2016
  • 3 рейтинг

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

    Вот официальный документ об операторе команды агрегации: https: // docs. MongoDB. ком / ручной / ссылки / оператор / агрегация / strcasecmp / # эксп. _S_strcasecmp .

    ответ дан Jogue Wasin, с репутацией 36, 20.05.2017
  • 2 рейтинг
    db.company_profile.find({ "companyName" : { "$regex" : "Nilesh" , "$options" : "i"}});
    
    ответ дан Nilesh, с репутацией 773, 4.09.2018
  • 1 рейтинг

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

    В следующем примере создается коллекция без сопоставления по умолчанию, затем добавляется индекс в поле имени с сопоставлением без учета регистра. Международные компоненты для 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
    
    ответ дан Gencebay D., с репутацией 303, 22.11.2017
  • 1 рейтинг

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

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

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

    escape-string-regexp

    ответ дан davidivad, с репутацией 457, 31.05.2018
  • 1 рейтинг

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

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

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

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

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

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

    ответ дан A_Arnold, с репутацией 1262, 7.08.2017
  • 0 рейтинг

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

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

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

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

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

    ответ дан Gouri Shankar, с репутацией 1, 3.07.2018
  • 0 рейтинг

    Как вы можете видеть в документах Монго - начиная с версии 3. 2 Индекс $text по умолчанию учитывает регистр: https: // docs. MongoDB. ru / manual / core / index-text / # text-index-case-insensitivity

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

    ответ дан avalanche1, с репутацией 730, 10.05.2017
  • 0 рейтинг

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

    {'_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
    
    ответ дан Ar maj, с репутацией 1064, 12.05.2017
  • 0 рейтинг

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

      const flavorExists = await Flavors.findOne({
        'flavor.name': { $regex: flavorName, $options: 'i' },
      });
    
    ответ дан Woppi, с репутацией 2188, 11.04.2018
  • 0 рейтинг

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

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

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

    db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();
    
    ответ дан Nitesh, с репутацией 554, 5.09.2015