Примечание для всех, кто попытается использовать ответ, включающий регулярные выражения: регулярные выражения необходимо очистить.
Шон
Ответы:
126
Решение Криса Фулстоу будет работать (+1), однако оно может быть неэффективным, особенно если ваша коллекция очень большая. Некорневые регулярные выражения (те, которые не начинаются с ^, которые привязывают регулярное выражение к началу строки) и те, которые используют iфлаг нечувствительности к регистру, не будут использовать индексы, даже если они существуют.
Альтернативный вариант, который вы можете рассмотреть, - денормализовать данные для хранения версии nameполя в нижнем регистре , например, как name_lower. Затем вы можете эффективно запросить это (особенно если оно проиндексировано) для точных совпадений без учета регистра, например:
Отличный ответ, мой подход с регулярным выражением действительно замедляется, когда ему приходится сканировать несколько миллионов документов.
Крис Фулстоу
34
На самом деле это не совсем правильно, потому что вы можете найти «Эндрю что-то» при поиске «Эндрю». Поэтому настройте регулярное выражение на: new RegExp('^'+ username + '$', "i")чтобы оно было точным.
Tarion
9
Согласно веб-сайту MongoDB, любое регулярное выражение без учета регистра не является эффективным с точки зрения индекса «$ regex может эффективно использовать индекс только в том случае, если регулярное выражение имеет привязку для начала (т. Е. ^) Строки и является совпадением с учетом регистра »,
Райан Шумахер,
2
С Mongoose это сработало для меня: User.find ({'username': {$ regex: new RegExp ('^' + username.toLowerCase (), 'i')}}, function (err, res) {if (err ) throw err; next (null, res);});
ChrisRich
5
Никогда не забывайте экранировать имя при работе с регулярными выражениями. Мы не хотим, чтобы инъекции захватили красоту mongodb. Только представьте, что вы использовали этот код для страницы входа, а имя пользователя было ".*".
Тобиас
90
Для этого вам нужно будет использовать регулярное выражение без учета регистра , например
MongoDB 3.4 теперь включает в себя возможность создавать индекс без учета регистра, что резко увеличит скорость поиска без учета регистра в больших наборах данных. Он создается путем указания сопоставления с силой 2.
Вероятно, самый простой способ сделать это - установить параметры сортировки в базе данных. Затем все запросы наследуют это сопоставление и будут использовать его:
Регулярные выражения работают медленнее, чем сопоставление буквальных строк. Однако дополнительное поле в нижнем регистре усложнит ваш код. В случае сомнений используйте регулярные выражения. Я бы посоветовал использовать поле с явно строчными буквами только в том случае, если оно может заменить ваше поле, то есть вас в первую очередь не волнует регистр.
Обратите внимание, что вам нужно будет экранировать имя до регулярного выражения. Если вам нужны подстановочные знаки, вводимые пользователем .replace(/%/g, '.*'), лучше добавлять их после экранирования, чтобы вы могли сопоставить «a%», чтобы найти все имена, начинающиеся с «a».
Вы можете использовать индексы без учета регистра :
В следующем примере создается коллекция без параметров сортировки по умолчанию, а затем добавляется индекс в поле имени с параметрами сортировки без учета регистра. Международные компоненты для 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 } )
или вы можете создать коллекцию с сопоставлением по умолчанию:
Ответы:
Решение Криса Фулстоу будет работать (+1), однако оно может быть неэффективным, особенно если ваша коллекция очень большая. Некорневые регулярные выражения (те, которые не начинаются с
^
, которые привязывают регулярное выражение к началу строки) и те, которые используютi
флаг нечувствительности к регистру, не будут использовать индексы, даже если они существуют.Альтернативный вариант, который вы можете рассмотреть, - денормализовать данные для хранения версии
name
поля в нижнем регистре , например, какname_lower
. Затем вы можете эффективно запросить это (особенно если оно проиндексировано) для точных совпадений без учета регистра, например:db.collection.find({"name_lower": thename.toLowerCase()})
Или с совпадением префикса (корневое регулярное выражение) как:
db.collection.find( {"name_lower": { $regex: new RegExp("^" + thename.toLowerCase(), "i") } } );
Оба этих запроса будут использовать индекс
name_lower
.источник
new RegExp('^'+ username + '$', "i")
чтобы оно было точным.".*"
.Для этого вам нужно будет использовать регулярное выражение без учета регистра , например
db.collection.find( { "name" : { $regex : /Andrew/i } } );
Чтобы использовать шаблон регулярного выражения из вашей
thename
переменной, создайте новый объект RegExp :var thename = "Andrew"; db.collection.find( { "name" : { $regex : new RegExp(thename, "i") } } );
Обновление: для точного совпадения вы должны использовать регулярное выражение
"name": /^Andrew$/i
. Благодаря Яннику Л.источник
name
, а не только равенству.{ "name": /^Andrew$/i }
Я решил это так.
var thename = 'Andrew'; db.collection.find({'name': {'$regex': thename,$options:'i'}});
Если вы хотите запросить «точное соответствие без учета регистра», вы можете сделать это следующим образом.
var thename = '^Andrew$'; db.collection.find({'name': {'$regex': thename,$options:'i'}});
источник
MongoDB 3.4 теперь включает в себя возможность создавать индекс без учета регистра, что резко увеличит скорость поиска без учета регистра в больших наборах данных. Он создается путем указания сопоставления с силой 2.
Вероятно, самый простой способ сделать это - установить параметры сортировки в базе данных. Затем все запросы наследуют это сопоставление и будут использовать его:
db.createCollection("cities", { collation: { locale: 'en_US', strength: 2 } } ) db.names.createIndex( { city: 1 } ) // inherits the default collation
Вы также можете сделать это так:
db.myCollection.createIndex({city: 1}, {collation: {locale: "en", strength: 2}});
И используйте это так:
db.myCollection.find({city: "new york"}).collation({locale: "en", strength: 2});
Это вернет города с названиями «Нью-Йорк», «Нью-Йорк», «Нью-Йорк» и т. Д.
Для получения дополнительной информации: https://jira.mongodb.org/browse/SERVER-90
источник
С Mongoose (и Node) это сработало:
User.find({ email: /^name@company.com$/i })
User.find({ email: new RegExp(
`^ $ {emailVariable} $`, 'i')})В MongoDB это сработало:
db.users.find({ email: { $regex: /^name@company.com$/i }})
Обе строки нечувствительны к регистру. Электронная почта в БД может быть,
NaMe@CompanY.Com
и обе строки все равно найдут объект в БД.Точно так же мы могли бы использовать,
/^NaMe@CompanY.Com$/i
и он все равно находил бы электронную почту:name@company.com
в БД.источник
Чтобы найти нечувствительную к регистру строку, используйте это,
var thename = "Andrew"; db.collection.find({"name":/^thename$/i})
источник
Я решил эту проблему несколько часов назад.
var thename = 'Andrew' db.collection.find({ $text: { $search: thename } });
Вы даже можете расширить это, выбрав нужные поля в пользовательском объекте Andrew, сделав это следующим образом:
db.collection.find({ $text: { $search: thename } }).select('age height weight');
Ссылка: https://docs.mongodb.org/manual/reference/operator/query/text/#text
источник
... с мангустом на NodeJS этот запрос:
const countryName = req.params.country; { 'country': new RegExp(`^${countryName}$`, 'i') };
или
const countryName = req.params.country; { 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } }; // ^australia$
или
const countryName = req.params.country; { 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } }; // ^turkey$
Полный пример кода на Javascript, NodeJS с Mongoose ORM на MongoDB
// get all customers that given country name app.get('/customers/country/:countryName', (req, res) => { //res.send(`Got a GET request at /customer/country/${req.params.countryName}`); const countryName = req.params.countryName; // using Regular Expression (case intensitive and equal): ^australia$ // const query = { 'country': new RegExp(`^${countryName}$`, 'i') }; // const query = { 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } }; const query = { 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } }; Customer.find(query).sort({ name: 'asc' }) .then(customers => { res.json(customers); }) .catch(error => { // error.. res.send(error.message); }); });
источник
Следующий запрос найдет документы с требуемой строкой нечувствительно и также с глобальным появлением
db.collection.find({name:{ $regex: new RegExp(thename, "ig") } },function(err, doc) { //Your code here... });
источник
Чтобы найти строку литералов без учета регистра:
Использование регулярного выражения (рекомендуется)
db.collection.find({ name: { $regex: new RegExp('^' + name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '$', 'i') } });
Использование строчного индекса (быстрее)
db.collection.find({ name_lower: name.toLowerCase() });
Регулярные выражения работают медленнее, чем сопоставление буквальных строк. Однако дополнительное поле в нижнем регистре усложнит ваш код. В случае сомнений используйте регулярные выражения. Я бы посоветовал использовать поле с явно строчными буквами только в том случае, если оно может заменить ваше поле, то есть вас в первую очередь не волнует регистр.
Обратите внимание, что вам нужно будет экранировать имя до регулярного выражения. Если вам нужны подстановочные знаки, вводимые пользователем
.replace(/%/g, '.*')
, лучше добавлять их после экранирования, чтобы вы могли сопоставить «a%», чтобы найти все имена, начинающиеся с «a».источник
Вы можете использовать индексы без учета регистра :
В следующем примере создается коллекция без параметров сортировки по умолчанию, а затем добавляется индекс в поле имени с параметрами сортировки без учета регистра. Международные компоненты для 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
источник
Простым способом было бы использовать $ toLower, как показано ниже.
db.users.aggregate([ { $project: { name: { $toLower: "$name" } } }, { $match: { name: the_name_to_search } } ])
источник