Пример:
> db.stuff.save({"foo":"bar"});
> db.stuff.find({"foo":"bar"}).count();
1
> db.stuff.find({"foo":"BAR"}).count();
0
Вы можете использовать regex.
В вашем примере это будет:
db.stuff.find( { foo: /^bar$/i } );
Я должен сказать, хотя, может быть, вы могли бы просто изменить (или высвободить) значение на пути, а не приносить дополнительную стоимость каждый раз, когда найдете его. Очевидно, что это не будет работать для имен людей и т.д., Но, возможно, для использования в виде тегов.
UPDATE:
Оригинальный ответ теперь устарел. Mongodb теперь поддерживает расширенный полнотекстовый поиск со многими функциями.
ОРИГИНАЛЬНЫЙ ОТВЕТ:
Следует отметить, что поиск с регистрозависимым регистром нечувствителен /i означает, что mongodb не может искать по индексу, поэтому запросы к большим наборам данных могут занять много времени.
Даже с небольшими наборами данных он не очень эффективен. Вы получаете гораздо больший хит процессора, чем ваши ордера на запрос, что может стать проблемой, если вы пытаетесь достичь масштаба.
В качестве альтернативы вы можете сохранить заглавную копию и выполнить поиск по ней. Например, у меня есть таблица User, у которой есть имя пользователя, которое является смешанным случаем, но идентификатор является заглавной копией имени пользователя. Это гарантирует, что дублирование с учетом регистра невозможно (наличие "Foo" и "foo" не будет разрешено), и я могу выполнить поиск по id = username.toUpperCase(), чтобы получить поиск по имени пользователя без учета регистра.
Если ваше поле большое, например тело сообщения, дублирование данных, вероятно, не является хорошим вариантом. Я считаю, что использование альтернативного индексатора, такого как Apache Lucene, является лучшим вариантом в этом случае.
Если вам нужно создать regexp из переменной, это гораздо лучший способ сделать это: https://stackoverflow.com/questions/10728043/mongo-query-with-regex-in-node-js-operating-on-a-variable
Затем вы можете сделать что-то вроде:
var string = "SomeStringToFind";
var regex = new RegExp(["^", string, "$"].join(""), "i");
// Creates a regex of: /^SomeStringToFind$/i
db.stuff.find( { foo: regex } );
Это имеет преимущество быть более программным, или вы можете получить повышение производительности путем компиляции его заранее, если вы многократно используете его.
new RegExp("^" + req.params.term.toLowerCase(), "i")
также работает отлично
Имейте в виду, что предыдущий пример:
db.stuff.find( { foo: /bar/i } );
приведет к тому, что каждая запись, содержащая бар, будет соответствовать запросу (bar1, barxyz, openbar), это может быть очень опасно для поиска имени пользователя в функции auth...
Возможно, вам потребуется сопоставить только поисковый запрос, используя соответствующий синтаксис regexp как:
db.stuff.find( { foo: /^bar$/i } );
См. http://www.regular-expressions.info/ для справки по синтаксису для регулярных выражений
Начиная с 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});
Это вернет "Нью-Йорк", "Нью-Йорк" и т.д.
В качестве альтернативы вы можете заставить все индексы использовать параметры сортировки по умолчанию при создании коллекции следующим образом:
db.createCollection("cities",{collation:{locale: "en", strength: 2}});
Преимущество этого метода заключается в значительном улучшении эффективности и скорости в больших наборах данных.
Для получения дополнительной информации: https://jira.mongodb.org/browse/SERVER-90, https://docs.mongodb.com/manual/reference/collation/
db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive
db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity
TL; DR
Не используйте RegExp
Go natural И использовать встроенную индексацию mongodb, поиск
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 }
]
)
Необходимо создать индекс в зависимости от того, какое ТЕКСТ поле, которое вы хотите искать, без запроса индексирования будет чрезвычайно медленным
db.articles.createIndex( { subject: "text" } )
db.articles.find( { $text: { $search: "coffee",$caseSensitive :true } } ) //FOR SENSITIVITY
db.articles.find( { $text: { $search: "coffee",$caseSensitive :false } } ) //FOR INSENSITIVITY
Mongo (текущая версия 2.0.0) не разрешает поиск по регистровым полям с индексированными полями - см. их документацию. Для неиндексированных полей регулярные выражения, перечисленные в других ответах, должны быть точными.
Используя Mongoose, это сработало для меня:
var find = function(username, next){
User.find({'username': {$regex: new RegExp('^' + username, 'i')}}, function(err, res){
if(err) throw err;
next(null, res);
});
}
.toLowerCase()
избыточным, если вы указываете флаг i
без .toLowerCase()
регистра?
Одна важная вещь, которую следует иметь в виду при использовании запроса на основе Regex. Когда вы делаете это для системы входа в систему, избегайте каждого символа, который вы ищете, и не забывайте операторы ^ и $. У Lodash есть хорошая функция для этого, если вы уже используете его:
db.stuff.find({$regex: new RegExp(_.escapeRegExp(bar), $options: 'i'})
Почему? Представьте, что пользователь вводит .*
в качестве своего имени пользователя. Это будет соответствовать всем именам пользователей, что позволит войти в систему, просто угадывая пароль пользователя.
Предположим, что вы хотите найти "столбец" в "Таблице", и вы хотите, чтобы поиск в 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".
Все самое лучшее.
Лучший способ заключается в выборе вашего языка при создании обертки модели для ваших объектов, попробуйте выполнить метод save() через набор полей, которые вы будете искать, которые также индексируются; эти группы полей должны иметь строчные копии, которые затем используются для поиска.
Каждый раз, когда объект снова сохраняется, свойства нижнего регистра затем проверяются и обновляются с любыми изменениями основных свойств. Это позволит вам эффективно искать, но скрыть дополнительную работу, необходимую для обновления полей lc каждый раз.
Поля нижнего регистра могут быть хранилищем объектов ключа: значение или просто имя поля с префиксом lc_. Я использую второй, чтобы упростить запрос (запросы на глубинные объекты иногда могут сбивать с толку).
Примечание: вы хотите индексировать поля lc_, а не основные поля, на которых они основаны.
db.company_profile.find({ "companyName" : { "$regex" : "Nilesh" , "$options" : "i"}});
Структура агрегации была введена в mongodb 2.2. Вы можете использовать строковый оператор "$ strcasecmp", чтобы сделать нечувствительное к регистру сравнение строк. Это более рекомендуется и проще, чем при использовании регулярного выражения.
Здесь официальный документ оператора оператора агрегации: https://docs.mongodb.com/manual/reference/operator/aggregation/strcasecmp/#exp._S_strcasecmp.
Для поиска и экранирования переменной:
const escapeStringRegexp = require('escape-string-regexp')
const name = 'foo'
db.stuff.find({name: new RegExp('^' + escapeStringRegexp(name) + '$', 'i')})
Выход из переменной защищает запрос от атак с помощью '. *' Или другого регулярного выражения.
Вы можете использовать Нечувствительные к регистру индексы:
В следующем примере создается коллекция без сортировки по умолчанию, а затем добавляется индекс в поле имени с учетом нечувствительности к регистру. Международные компоненты для Юникода
/* 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
db.users.createIndex( { name: 1 }, {collation: { locale: 'tr', strength: 2 } } )
Использование фильтра работает для меня на С#.
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() является свойством и не будет правильно отображаться.
Для любого, кто использует Golang и хочет иметь полнотекстовый поиск с учетом регистра с помощью mongodb и библиотеки globalsign mgo godoc.
collation := &mgo.Collation{
Locale: "en",
Strength: 2,
}
err := collection.Find(query).Collation(collation)
Используйте RegExp, в случае, если какие-либо другие варианты не работают для вас, RegExp является хорошим вариантом. Это делает строку чувствительной к регистру.
var username = "John";
var uname = new RegExp(username, "i");
Значение uname
будет похоже на /John/i
.
используйте uname в запросах вместо имени пользователя, и тогда все готово.
Я надеюсь, что это сработает и для вас. Всего наилучшего.
Я столкнулся с подобной проблемой, и это то, что работает для меня:
const flavorExists = await Flavors.findOne({
'flavor.name': { $regex: flavorName, $options: 'i' },
});
Они были протестированы для поиска строк
{'_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
Как вы можете видеть в mongo docs - поскольку версия 3.2 $text
по умолчанию не учитывает регистр: https://docs.mongodb.com/manual/core/index-text/#text-index-case-insensitivity
Создать текстовый индекс и использовать $text operator в вашем запрос.
Я создал простой Func для нечувствительного к регистру регулярного выражения, которое я использую в своем фильтре.
private Func<string, BsonRegularExpression> CaseInsensitiveCompare = (field) =>
BsonRegularExpression.Create(new Regex(field, RegexOptions.IgnoreCase));
Затем вы просто фильтруете поле в следующем виде.
db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();
$caseSensitive: false
регистра с помощью$caseSensitive: false
. См .: docs.mongodb.org/manual/reference/operator/query/text/…