Uwaga dla wszystkich, którzy spróbują użyć odpowiedzi zawierającej wyrażenia regularne: Regeksy muszą zostać oczyszczone.
sean
Odpowiedzi:
126
Rozwiązanie Chrisa Fulstowa zadziała (+1), jednak może nie być wydajne, zwłaszcza jeśli twoja kolekcja jest bardzo duża. Niezakorzenione wyrażenia regularne (te, które nie rozpoczynają się od ^, które zakotwiczają wyrażenie regularne na początku ciągu) oraz te, które używają iflagi dla niewrażliwości na wielkość liter, nie będą używać indeksów, nawet jeśli istnieją.
Alternatywną opcją, którą możesz rozważyć, jest denormalizacja danych w celu zapisania wersji namepola z małymi literami , na przykład jako name_lower. Następnie możesz efektywnie zapytać (zwłaszcza jeśli jest indeksowany) o dokładne dopasowania bez rozróżniania wielkości liter, takie jak:
Świetna odpowiedź, moje podejście do wyrażeń regularnych naprawdę zwalnia, gdy musi przeskanować kilka milionów dokumentów.
Chris Fulstow,
34
W rzeczywistości nie jest to do końca poprawne, ponieważ możesz znaleźć „Andrew coś”, szukając słowa „Andrew”. Więc dostosuj wyrażenie regularne do: new RegExp('^'+ username + '$', "i")aby być dokładnym dopasowaniem.
Tarion,
9
Według witryny MongoDB żadne wyrażenie regularne bez rozróżniania wielkości liter nie jest indeksowane "$ regex może efektywnie używać indeksu tylko wtedy, gdy wyrażenie regularne ma kotwicę na początku (tj. ^) Ciągu i jest dopasowywane z rozróżnianiem wielkości liter "
Ryan Schumacher
2
Z Mongoose to zadziałało dla mnie: User.find ({'username': {$ regex: new RegExp ('^' + username.toLowerCase (), 'i')}}, function (err, res) {if (err ) rzucać błąd; next (null, res);});
ChrisRich,
5
Podczas pracy z wyrażeniami regularnymi nigdy nie zapomnij o ucieczce przed nazwą. Nie chcemy, aby zastrzyki przejęły piękno mongodb. Wyobraź sobie, że użyłeś tego kodu na stronie logowania, a nazwa użytkownika to ".*".
MongoDB 3.4 zawiera teraz możliwość tworzenia prawdziwego indeksu bez rozróżniania wielkości liter, co znacznie zwiększy szybkość wyszukiwania bez rozróżniania wielkości liter w dużych zestawach danych. Dokonuje się tego przez określenie zestawienia o sile 2.
Prawdopodobnie najłatwiejszym sposobem jest ustawienie sortowania w bazie danych. Następnie wszystkie zapytania dziedziczą to sortowanie i będą z niego korzystać:
W obu wierszach wielkość liter nie jest rozróżniana. E-mail w bazie danych mógłby być[email protected] a obie linie nadal będą znajdować obiekt w bazie danych.
Wyrażenia regularne są wolniejsze niż dopasowywanie literałów. Jednak dodatkowe pole z małą literą zwiększy złożoność kodu. W razie wątpliwości użyj wyrażeń regularnych. Sugerowałbym użycie pola z wyraźnie małymi literami tylko wtedy, gdy może ono zastąpić twoje pole, to znaczy nie przejmujesz się wielkością liter.
Pamiętaj, że przed wprowadzeniem wyrażenia regularnego będziesz musiał uciec przed nazwą. Jeśli chcesz .replace(/%/g, '.*')używać symboli wieloznacznych wprowadzanych przez użytkownika, preferuj dołączanie po znaku ucieczki, aby można było dopasować „a%”, aby znaleźć wszystkie nazwy zaczynające się od „a”.
Możesz użyć indeksów bez rozróżniania wielkości liter :
Poniższy przykład tworzy kolekcję bez domyślnego sortowania, a następnie dodaje indeks do pola nazwy z sortowaniem bez uwzględniania wielkości liter. Komponenty międzynarodowe dla 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 } } )
Aby użyć indeksu, kwerendy muszą określać to samo sortowanie.
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 } )
lub możesz utworzyć kolekcję z domyślnym sortowaniem:
Odpowiedzi:
Rozwiązanie Chrisa Fulstowa zadziała (+1), jednak może nie być wydajne, zwłaszcza jeśli twoja kolekcja jest bardzo duża. Niezakorzenione wyrażenia regularne (te, które nie rozpoczynają się od
^
, które zakotwiczają wyrażenie regularne na początku ciągu) oraz te, które używająi
flagi dla niewrażliwości na wielkość liter, nie będą używać indeksów, nawet jeśli istnieją.Alternatywną opcją, którą możesz rozważyć, jest denormalizacja danych w celu zapisania wersji
name
pola z małymi literami , na przykład jakoname_lower
. Następnie możesz efektywnie zapytać (zwłaszcza jeśli jest indeksowany) o dokładne dopasowania bez rozróżniania wielkości liter, takie jak:db.collection.find({"name_lower": thename.toLowerCase()})
Lub z dopasowaniem prefiksu (zakorzenione wyrażenie regularne) jako:
db.collection.find( {"name_lower": { $regex: new RegExp("^" + thename.toLowerCase(), "i") } } );
Oba te zapytania będą używać indeksu
name_lower
.źródło
new RegExp('^'+ username + '$', "i")
aby być dokładnym dopasowaniem.".*"
.W tym przypadku musiałbyś użyć wyrażenia regularnego bez rozróżniania wielkości liter , np
db.collection.find( { "name" : { $regex : /Andrew/i } } );
Aby użyć wzorca wyrażenia regularnego ze
thename
zmiennej, utwórz nowy obiekt RegExp :var thename = "Andrew"; db.collection.find( { "name" : { $regex : new RegExp(thename, "i") } } );
Aktualizacja: aby uzyskać dokładne dopasowanie, użyj wyrażenia regularnego
"name": /^Andrew$/i
. Dzięki Yannick L.źródło
name
, a nie tylko z równaniem.{ "name": /^Andrew$/i }
Rozwiązałem to w ten sposób.
var thename = 'Andrew'; db.collection.find({'name': {'$regex': thename,$options:'i'}});
Jeśli chcesz zapytać o „dopasowanie ścisłe bez rozróżniania wielkości liter”, możesz to zrobić w ten sposób.
var thename = '^Andrew$'; db.collection.find({'name': {'$regex': thename,$options:'i'}});
źródło
MongoDB 3.4 zawiera teraz możliwość tworzenia prawdziwego indeksu bez rozróżniania wielkości liter, co znacznie zwiększy szybkość wyszukiwania bez rozróżniania wielkości liter w dużych zestawach danych. Dokonuje się tego przez określenie zestawienia o sile 2.
Prawdopodobnie najłatwiejszym sposobem jest ustawienie sortowania w bazie danych. Następnie wszystkie zapytania dziedziczą to sortowanie i będą z niego korzystać:
db.createCollection("cities", { collation: { locale: 'en_US', strength: 2 } } ) db.names.createIndex( { city: 1 } ) // inherits the default collation
Możesz to również zrobić w ten sposób:
db.myCollection.createIndex({city: 1}, {collation: {locale: "en", strength: 2}});
I użyj tego w ten sposób:
db.myCollection.find({city: "new york"}).collation({locale: "en", strength: 2});
Spowoduje to zwrócenie miast o nazwach „Nowy Jork”, „Nowy Jork”, „Nowy Jork” itp.
Więcej informacji: https://jira.mongodb.org/browse/SERVER-90
źródło
W przypadku Mongoose (i Node) to zadziałało:
User.find({ email: /^[email protected]$/i })
User.find({ email: new RegExp(
`^ $ {emailVariable} $`, 'i')})W MongoDB to zadziałało:
db.users.find({ email: { $regex: /^[email protected]$/i }})
W obu wierszach wielkość liter nie jest rozróżniana. E-mail w bazie danych mógłby być
[email protected]
a obie linie nadal będą znajdować obiekt w bazie danych.Podobnie moglibyśmy użyć
/^[email protected]$/i
i nadal znajdowałby email:[email protected]
w bazie danych.źródło
Aby znaleźć ciąg niewrażliwy na wielkość liter, użyj tego,
var thename = "Andrew"; db.collection.find({"name":/^thename$/i})
źródło
Właśnie rozwiązałem ten problem kilka godzin temu.
var thename = 'Andrew' db.collection.find({ $text: { $search: thename } });
Możesz nawet rozszerzyć ten zakres, wybierając potrzebne pola z obiektu użytkownika Andrew, robiąc to w ten sposób:
db.collection.find({ $text: { $search: thename } }).select('age height weight');
Źródła: https://docs.mongodb.org/manual/reference/operator/query/text/#text
źródło
... z mongoose w NodeJS, które zapytanie:
const countryName = req.params.country; { 'country': new RegExp(`^${countryName}$`, 'i') };
lub
const countryName = req.params.country; { 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } }; // ^australia$
lub
const countryName = req.params.country; { 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } }; // ^turkey$
Przykład pełnego kodu w JavaScript, NodeJS z Mongoose ORM w 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); }); });
źródło
Następujące zapytanie znajdzie dokumenty z wymaganym ciągiem bez uwzględnienia, a także z wystąpieniem globalnym
db.collection.find({name:{ $regex: new RegExp(thename, "ig") } },function(err, doc) { //Your code here... });
źródło
Aby znaleźć ciąg literałów bez rozróżniania wielkości liter:
Korzystanie z wyrażenia regularnego (zalecane)
db.collection.find({ name: { $regex: new RegExp('^' + name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '$', 'i') } });
Korzystanie z małych liter (szybciej)
db.collection.find({ name_lower: name.toLowerCase() });
Wyrażenia regularne są wolniejsze niż dopasowywanie literałów. Jednak dodatkowe pole z małą literą zwiększy złożoność kodu. W razie wątpliwości użyj wyrażeń regularnych. Sugerowałbym użycie pola z wyraźnie małymi literami tylko wtedy, gdy może ono zastąpić twoje pole, to znaczy nie przejmujesz się wielkością liter.
Pamiętaj, że przed wprowadzeniem wyrażenia regularnego będziesz musiał uciec przed nazwą. Jeśli chcesz
.replace(/%/g, '.*')
używać symboli wieloznacznych wprowadzanych przez użytkownika, preferuj dołączanie po znaku ucieczki, aby można było dopasować „a%”, aby znaleźć wszystkie nazwy zaczynające się od „a”.źródło
Możesz użyć indeksów bez rozróżniania wielkości liter :
Poniższy przykład tworzy kolekcję bez domyślnego sortowania, a następnie dodaje indeks do pola nazwy z sortowaniem bez uwzględniania wielkości liter. Komponenty międzynarodowe dla 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 } } )
Aby użyć indeksu, kwerendy muszą określać to samo sortowanie.
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 } )
lub możesz utworzyć kolekcję z domyślnym sortowaniem:
db.createCollection("users", { collation: { locale: 'tr', strength: 2 } } ) db.users.createIndex( { name : 1 } ) // inherits the default collation
źródło
Prostym sposobem byłoby użycie $ toLower, jak poniżej.
db.users.aggregate([ { $project: { name: { $toLower: "$name" } } }, { $match: { name: the_name_to_search } } ])
źródło