db.stuff.find({"foo":"bar"}).count();1> db.stuff.find({"foo":"BAR"}).count();0" />

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

mongodb case-insensitive

210767 просмотра

23 ответа

7207 Репутация автора

Пример:

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

> db.stuff.find({"foo":"bar"}).count();
1
> db.stuff.find({"foo":"BAR"}).count();
0
Автор: Luke Dennis Источник Размещён: 07.12.2009 10:36

Ответы (23)


299 плюса

26316 Репутация автора

Решение

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

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

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

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

Автор: rfunduk Размещён: 07.12.2009 10:46

190 плюса

2453 Репутация автора

ОБНОВИТЬ:

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

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

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

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

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

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

Автор: Dan Размещён: 14.12.2010 04:22

6 плюса

3414 Репутация автора

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

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

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

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

Автор: RobKohr Размещён: 20.04.2011 05:30

58 плюса

1579 Репутация автора

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

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

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

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

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

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

Автор: jflaflamme Размещён: 03.06.2011 08:59

8 плюса

3063 Репутация автора

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

Автор: Aidan Feldman Размещён: 24.10.2011 07:31

56 плюса

2758 Репутация автора

Если вам нужно создать регулярное выражение из переменной, это гораздо лучший способ сделать это: 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 Размещён: 12.07.2012 08:39

5 плюса

2637 Репутация автора

Используя 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 Размещён: 16.10.2014 04:54

0 плюса

589 Репутация автора

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

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

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

db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();
Автор: Nitesh Размещён: 05.09.2015 11:18

16 плюса

179 Репутация автора

db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive
db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity
Автор: rshivamca Размещён: 17.12.2015 12:57

5 плюса

2981 Репутация автора

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

//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 Размещён: 30.04.2016 02:44

5 плюса

51 Репутация автора

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

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

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

Автор: Nick Kamer Размещён: 06.05.2016 09:01

14 плюса

4968 Репутация автора

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 :

Необходимо создать индекс для любого поля 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
Автор: vijay Размещён: 27.08.2016 07:29

35 плюса

4802 Репутация автора

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

Я лично написал одному из основателей, чтобы он заработал, и он сделал это! Это была проблема JIRA с 2009 года , и многие просили эту функцию. Вот как это работает:

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

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

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

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

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

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

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

Другие заметки

  • Ответы, предлагающие использовать полнотекстовый поиск, в этом случае неверны (и потенциально опасны ). Вопрос о создании запроса к регистру, например , username: 'bill'соответствие BILLили Billне поисковый запрос полный текст, который будет также соответствовать стеблях слова bill, например Bills, и billedт.д.
  • Ответы, предлагающие использовать регулярные выражения, являются медленными, потому что даже с индексами документация гласит :

    «Запросы регулярного выражения без учета регистра обычно не могут эффективно использовать индексы. Реализация $ regex не учитывает параметры сортировки и не может использовать индексы без учета регистра».

    $regexответы также рискуют ввести пользовательский ввод .

Автор: user3413723 Размещён: 01.12.2016 03:47

-1 плюса

810 Репутация автора

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

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

Автор: avalanche1 Размещён: 10.05.2017 03:40

-1 плюса

1240 Репутация автора

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

{'_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 Размещён: 12.05.2017 02:42

3 плюса

42 Репутация автора

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

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

Автор: Jogue Wasin Размещён: 20.05.2017 04:20

0 плюса

1295 Репутация автора

Использование фильтра работает для меня в 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 () является свойством и не будет отображаться правильно.

Автор: A_Arnold Размещён: 07.08.2017 05:09

3 плюса

343 Репутация автора

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

В следующем примере создается коллекция без сопоставления по умолчанию, затем добавляется индекс в поле имени с сопоставлением без учета регистра. Международные компоненты для 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. Размещён: 22.11.2017 04:19

-1 плюса

2636 Репутация автора

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

  const flavorExists = await Flavors.findOne({
    'flavor.name': { $regex: flavorName, $options: 'i' },
  });
Автор: Woppi Размещён: 11.04.2018 07:36

2 плюса

577 Репутация автора

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

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

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

бежать строка-регулярное выражение

Автор: davidivad Размещён: 31.05.2018 10:14

0 плюса

23 Репутация автора

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

var username = new RegExp("^" + "John" + "$", "i");;

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

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

Автор: Gouri Shankar Размещён: 03.07.2018 05:06

9 плюса

1047 Репутация автора

db.company_profile.find({ "companyName" : { "$regex" : "Nilesh" , "$options" : "i"}});
Автор: Nilesh Размещён: 04.09.2018 02:37

0 плюса

1911 Репутация автора

Для любого из использования Golang и желает иметь дела чувствительную полнотекстовый поиск с MongoDB и ГГО godoc Globalsign библиотеки .

collation := &mgo.Collation{
    Locale:   "en",
    Strength: 2, 
}


err := collection.Find(query).Collation(collation)
Автор: okandas Размещён: 13.12.2018 02:13
Вопросы из категории :
32x32