Ein Hinweis an alle, die versuchen werden, eine Antwort mit regulären Ausdrücken zu verwenden: Regexe müssen bereinigt werden.
Sean
Antworten:
122
Die Lösung von Chris Fulstow funktioniert (+1), ist jedoch möglicherweise nicht effizient, insbesondere wenn Ihre Sammlung sehr groß ist. Nicht verwurzelte reguläre Ausdrücke (diejenigen, die nicht mit beginnen ^und den regulären Ausdruck am Anfang der Zeichenfolge verankern) und diejenigen, die das iFlag für Groß- und Kleinschreibung verwenden, verwenden keine Indizes, selbst wenn sie vorhanden sind.
Eine alternative Option, die Sie in Betracht ziehen könnten, besteht darin, Ihre Daten zu denormalisieren, um eine Kleinbuchstabenversion des nameFelds zu speichern , z name_lower. Sie können dies dann effizient abfragen (insbesondere wenn es indiziert ist), um genaue Übereinstimmungen ohne Berücksichtigung der Groß- und Kleinschreibung zu berücksichtigen, z.
Tolle Antwort, mein Regex-Ansatz verlangsamt sich wirklich, wenn ein paar Millionen Dokumente gescannt werden müssen.
Chris Fulstow
33
Dies ist eigentlich nicht ganz richtig, da Sie möglicherweise "Andrew etwas" finden, während Sie nach "Andrew" suchen. Passen Sie den regulären Ausdruck also an: new RegExp('^'+ username + '$', "i")um eine genaue Übereinstimmung zu erhalten.
Tarion
9
Laut der MongoDB-Website ist ein regulärer Ausdruck ohne Berücksichtigung des Index nicht indexwirksam. "$ Regex kann einen Index nur dann effizient verwenden, wenn der reguläre Ausdruck einen Anker für den Anfang (dh ^) eines Strings hat und zwischen Groß- und Kleinschreibung unterscheidet "
Ryan Schumacher
2
Bei Mongoose funktionierte dies für mich: User.find ({'Benutzername': {$ regex: new RegExp ('^' + Benutzername.toLowerCase (), 'i')}}, Funktion (err, res) {if (err ) wirf err; next (null, res);});
ChrisRich
5
Vergessen Sie niemals, dem Namen zu entkommen, wenn Sie mit regulären Ausdrücken arbeiten. Wir wollen nicht, dass Injektionen die Schönheit von Mongodb übernehmen. Stellen Sie sich vor, Sie haben diesen Code für eine Anmeldeseite verwendet und der Benutzername war ".*".
Tobias
86
Sie müssten für diesen einen regulären Ausdruck verwenden, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird , z
Bei beiden Zeilen wird die Groß- und Kleinschreibung nicht berücksichtigt. Die E-Mail in der DB könnte sein[email protected] und beide Zeilen finden das Objekt weiterhin in der Datenbank.
MongoDB 3.4 bietet jetzt die Möglichkeit, einen echten Index ohne Berücksichtigung der Groß- und Kleinschreibung zu erstellen, wodurch die Geschwindigkeit der Suche nach Groß- und Kleinschreibung bei großen Datenmengen drastisch erhöht wird. Es wird durch Angabe einer Kollatierung mit einer Stärke von 2 erstellt.
Der wahrscheinlich einfachste Weg, dies zu tun, besteht darin, eine Sortierung in der Datenbank festzulegen. Dann erben alle Abfragen diese Sortierung und verwenden sie:
db.createCollection("cities",{ collation:{ locale:'en_US', strength:2}})
db.names.createIndex({ city:1})// inherits the default collation
Ein vollständiges Codebeispiel in Javascript, NodeJS mit Mongoose ORM in 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:newRegExp(`^${countryName}$`), $options:'i'}};Customer.find(query).sort({ name:'asc'}).then(customers =>{
res.json(customers);}).catch(error =>{// error..
res.send(error.message);});});
Reguläre Ausdrücke sind langsamer als der Literal-String-Abgleich. Ein zusätzliches Kleinbuchstabenfeld erhöht jedoch die Codekomplexität. Verwenden Sie im Zweifelsfall reguläre Ausdrücke. Ich würde vorschlagen, ein explizit klein geschriebenes Feld nur zu verwenden, wenn es Ihr Feld ersetzen kann, das heißt, Sie interessieren sich überhaupt nicht für den Fall.
Beachten Sie, dass Sie den Namen vor dem regulären Ausdruck maskieren müssen. Wenn Sie Platzhalter für Benutzereingaben wünschen, ziehen Sie es vor, .replace(/%/g, '.*')nach dem Escapezeichen anzuhängen , damit Sie mit "a%" übereinstimmen können, um alle Namen zu finden, die mit "a" beginnen.
Sie können Indizes verwenden, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird :
Im folgenden Beispiel wird eine Sammlung ohne Standardkollatierung erstellt und anschließend ein Index für das Namensfeld mit einer Sortierung hinzugefügt, bei der die Groß- und Kleinschreibung nicht berücksichtigt wird. Internationale Komponenten für 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}})
Um den Index verwenden zu können, müssen Abfragen dieselbe Sortierung angeben.
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})
oder Sie können eine Sammlung mit Standardkollatierung erstellen:
db.createCollection("users",{ collation:{ locale:'tr', strength:2}})
db.users.createIndex({ name :1})// inherits the default collation
Antworten:
Die Lösung von Chris Fulstow funktioniert (+1), ist jedoch möglicherweise nicht effizient, insbesondere wenn Ihre Sammlung sehr groß ist. Nicht verwurzelte reguläre Ausdrücke (diejenigen, die nicht mit beginnen
^
und den regulären Ausdruck am Anfang der Zeichenfolge verankern) und diejenigen, die dasi
Flag für Groß- und Kleinschreibung verwenden, verwenden keine Indizes, selbst wenn sie vorhanden sind.Eine alternative Option, die Sie in Betracht ziehen könnten, besteht darin, Ihre Daten zu denormalisieren, um eine Kleinbuchstabenversion des
name
Felds zu speichern , zname_lower
. Sie können dies dann effizient abfragen (insbesondere wenn es indiziert ist), um genaue Übereinstimmungen ohne Berücksichtigung der Groß- und Kleinschreibung zu berücksichtigen, z.Oder mit einer Präfixübereinstimmung (einem verwurzelten regulären Ausdruck) als:
Beide Abfragen verwenden einen Index für
name_lower
.quelle
new RegExp('^'+ username + '$', "i")
um eine genaue Übereinstimmung zu erhalten.".*"
.Sie müssten für diesen einen regulären Ausdruck verwenden, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird , z
Erstellen Sie
thename
ein neues RegExp- Objekt, um das Regex-Muster aus Ihrer Variablen zu verwenden :Update: Für eine genaue Übereinstimmung sollten Sie den regulären Ausdruck verwenden
"name": /^Andrew$/i
. Vielen Dank an Yannick L.quelle
name
, nicht nur gleich.{ "name": /^Andrew$/i }
Ich habe es so gelöst.
Wenn Sie nach "exakter Übereinstimmung ohne Berücksichtigung der Groß- und Kleinschreibung" fragen möchten, können Sie wie folgt vorgehen.
quelle
Mit Mongoose (und Node) funktionierte dies:
User.find({ email: /^[email protected]$/i })
User.find({ email: new RegExp(
`^ $ {emailVariable} $`, 'i')})In MongoDB funktionierte dies:
db.users.find({ email: { $regex: /^[email protected]$/i }})
Bei beiden Zeilen wird die Groß- und Kleinschreibung nicht berücksichtigt. Die E-Mail in der DB könnte sein
[email protected]
und beide Zeilen finden das Objekt weiterhin in der Datenbank.Ebenso könnten wir verwenden
/^[email protected]$/i
und es würde immer noch E-Mail finden:[email protected]
in der DB.quelle
MongoDB 3.4 bietet jetzt die Möglichkeit, einen echten Index ohne Berücksichtigung der Groß- und Kleinschreibung zu erstellen, wodurch die Geschwindigkeit der Suche nach Groß- und Kleinschreibung bei großen Datenmengen drastisch erhöht wird. Es wird durch Angabe einer Kollatierung mit einer Stärke von 2 erstellt.
Der wahrscheinlich einfachste Weg, dies zu tun, besteht darin, eine Sortierung in der Datenbank festzulegen. Dann erben alle Abfragen diese Sortierung und verwenden sie:
Sie können es auch so machen:
Und benutze es so:
Dadurch werden Städte mit den Namen "New York", "New York", "New York" usw. zurückgegeben.
Für weitere Informationen: https://jira.mongodb.org/browse/SERVER-90
quelle
Verwenden Sie diese Zeichenfolge, um eine Zeichenfolge ohne Berücksichtigung der Groß- und Kleinschreibung zu finden.
quelle
Ich habe dieses Problem erst vor ein paar Stunden gelöst.
Sie können dies sogar erweitern, indem Sie die Felder auswählen, die Sie aus Andrews Benutzerobjekt benötigen. Gehen Sie dazu folgendermaßen vor:
Referenz: https://docs.mongodb.org/manual/reference/operator/query/text/#text
quelle
... mit Mungo auf NodeJS diese Abfrage:
oder
oder
Ein vollständiges Codebeispiel in Javascript, NodeJS mit Mongoose ORM in MongoDB
quelle
Die folgende Abfrage findet die Dokumente mit der erforderlichen Zeichenfolge unempfindlich und auch mit globalem Vorkommen
quelle
So finden Sie eine Zeichenfolge, bei der die Groß- und Kleinschreibung nicht berücksichtigt wird:
Verwendung von Regex (empfohlen)
Kleinbuchstabenindex verwenden (schneller)
Reguläre Ausdrücke sind langsamer als der Literal-String-Abgleich. Ein zusätzliches Kleinbuchstabenfeld erhöht jedoch die Codekomplexität. Verwenden Sie im Zweifelsfall reguläre Ausdrücke. Ich würde vorschlagen, ein explizit klein geschriebenes Feld nur zu verwenden, wenn es Ihr Feld ersetzen kann, das heißt, Sie interessieren sich überhaupt nicht für den Fall.
Beachten Sie, dass Sie den Namen vor dem regulären Ausdruck maskieren müssen. Wenn Sie Platzhalter für Benutzereingaben wünschen, ziehen Sie es vor,
.replace(/%/g, '.*')
nach dem Escapezeichen anzuhängen , damit Sie mit "a%" übereinstimmen können, um alle Namen zu finden, die mit "a" beginnen.quelle
Sie können Indizes verwenden, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird :
Im folgenden Beispiel wird eine Sammlung ohne Standardkollatierung erstellt und anschließend ein Index für das Namensfeld mit einer Sortierung hinzugefügt, bei der die Groß- und Kleinschreibung nicht berücksichtigt wird. Internationale Komponenten für Unicode
Um den Index verwenden zu können, müssen Abfragen dieselbe Sortierung angeben.
oder Sie können eine Sammlung mit Standardkollatierung erstellen:
quelle
Ein einfacher Weg wäre, $ toLower wie unten zu verwenden.
quelle