it-swarm.com.de

MongoDB: Ist es möglich, eine Groß-/Kleinschreibung zu machen?

Beispiel:

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

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

Sie könnten eine regex verwenden.

In Ihrem Beispiel wäre das:

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

Ich muss jedoch sagen, dass Sie vielleicht den Wert auf dem Weg hinunter herabsetzen (oder hochstufen können), anstatt die zusätzlichen Kosten jedes Mal zu tragen, wenn Sie ihn finden. Offensichtlich funktioniert das nicht für die Namen von Personen und dergleichen, aber vielleicht auch Anwendungsfälle wie Tags.

285
rfunduk

UPDATE:

Die ursprüngliche Antwort ist veraltet. Mongodb unterstützt jetzt die erweiterte Volltextsuche mit vielen Funktionen.

ORIGINAL ANTWORT:

Es sollte beachtet werden, dass die Suche mit der Groß-/Kleinschreibung nach regex/i bedeutet, dass mongodb nicht nach einem Index suchen kann, sodass Abfragen gegen große Datensätze sehr lange dauern können. 

Selbst bei kleinen Datensätzen ist das nicht sehr effizient. Sie haben einen weitaus größeren CPU-Treffer als Ihre Abfrage-Warrants. Dies kann zu einem Problem werden, wenn Sie versuchen, eine Skalierung zu erreichen.

Alternativ können Sie eine Kopie in Großbuchstaben speichern und danach suchen. Zum Beispiel habe ich eine User-Tabelle, die einen Benutzernamen hat, der aus Groß- und Kleinschreibung besteht, aber die ID ist eine Kopie des Benutzernamens in Großbuchstaben. Dadurch wird sichergestellt, dass die Groß-/Kleinschreibung nicht berücksichtigt wird (sowohl "Foo" als auch "Foo" sind nicht zulässig). Ich kann mit id = username.toUpperCase () nach Groß- und Kleinschreibung nach Benutzernamen suchen.

Wenn Ihr Feld groß ist, z. B. ein Nachrichtentext, ist das Duplizieren von Daten wahrscheinlich keine gute Option. Ich glaube, dass die Verwendung eines externen Indexers wie Apache Lucene in diesem Fall die beste Option ist.

190
Dan

Beachten Sie, dass das vorige Beispiel:

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

bewirkt, dass alle Einträge, die bar enthalten, mit der Abfrage übereinstimmen (bar1, barxyz, openbar). Dies kann sehr gefährlich für eine Benutzername-Suche in einer Auth-Funktion sein ...

Möglicherweise müssen Sie nur den Suchbegriff anpassen, indem Sie die entsprechende Regex-Syntax verwenden:

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

Unter http://www.regular-expressions.info/ finden Sie Hilfe zur Syntax zu regulären Ausdrücken

58
jflaflamme

Wenn Sie den Regex aus einer Variablen erstellen müssen, ist dies eine viel bessere Methode: https://stackoverflow.com/a/10728069/309514

Sie können dann so etwas tun:

var string = "SomeStringToFind";
var regex = new RegExp(["^", string, "$"].join(""), "i");
// Creates a regex of: /^SomeStringToFind$/i
db.stuff.find( { foo: regex } );

Dies hat den Vorteil, dass es programmatischer ist, oder Sie können die Leistung steigern, indem Sie es vorab kompilieren, wenn Sie es häufig wiederverwenden.

56
Fotios

Ab Mongodb 3.4 sollten Sie einen Sortierindex verwenden, bei dem die Groß-/Kleinschreibung nicht berücksichtigt wird. Dies ist der schnellste Weg, eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung für Datensätze von immer größerer Größe durchzuführen. Ich persönlich habe einem der Gründer eine E-Mail geschickt, damit das funktionieren kann, und er hat es möglich gemacht! (Es war ein Problem für JIRA für 5 Jahre, und viele haben das Feature angefordert). So funktioniert das:

Ein Index ohne Berücksichtigung der Groß- und Kleinschreibung wird durch Angabe einer Kollatierung mit einer Stärke von 1 oder 2 erstellt. Sie können einen Index ohne Unterscheidung zwischen Groß- und Kleinschreibung wie folgt erstellen:

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

Oder Sie können dies standardmäßig für die gesamte Sammlung tun, wenn Sie die Datenbank wie folgt erstellen:

db.createCollection("Cities",{collation: {locale: "en",strength:2}});

Und benutze es so:

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

Dadurch werden "New York", "New York" usw. zurückgegeben.

Alternativ können Sie festlegen, dass alle Indizes standardmäßig eine Kollatierung verwenden, wenn Sie die Auflistung wie folgt erstellen:

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

Der Vorteil dieser Methode liegt in einer deutlich verbesserten Effizienz und Geschwindigkeit bei größeren Datensätzen.

Weitere Informationen: https://jira.mongodb.org/browse/SERVER-90 , https://docs.mongodb.com/manual/reference/collation/

26
user3413723
db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive
db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity
16
rshivamca

TL; DR

Richtige Vorgehensweise im Mongo

RegExp nicht verwenden

Gehen Sie natürlich Und verwenden Sie die eingebaute Indizierung von Mongodb, Suche

Schritt 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 }
   ]
)

Schritt 2 :

Sie müssen einen Index für das Feld TEXT erstellen, das Sie durchsuchen möchten 

db.articles.createIndex( { subject: "text" } )

schritt 3 :

db.articles.find( { $text: { $search: "coffee",$caseSensitive :true } } )  //FOR SENSITIVITY
db.articles.find( { $text: { $search: "coffee",$caseSensitive :false } } ) //FOR INSENSITIVITY
13
vijay

Mongo (aktuelle Version 2.0.0) erlaubt keine Suche nach Groß- und Kleinschreibung gegen indizierte Felder - siehe deren Dokumentation . Bei nicht indizierten Feldern sollten die in den anderen Antworten aufgeführten Ausdrücke in Ordnung sein.

9
Aidan Feldman

Mit Mongoose funktionierte das für mich:

var find = function(username, next){
    User.find({'username': {$regex: new RegExp('^' + username, 'i')}}, function(err, res){
        if(err) throw err;
        next(null, res);
    });
}
6
ChrisRich

Eine sehr wichtige Sache, die Sie bei der Verwendung einer auf Regex basierenden Abfrage berücksichtigen sollten: - Wenn Sie dies für ein Anmeldesystem tun, entgehen Sie jedes einzelne Zeichen , nach dem Sie suchen, und/und vergessen Sie nicht die ^ und $ - Operatoren. Lodash hat eine Nice-Funktion dafür , falls du es schon benutzt:

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

Warum? Stellen Sie sich vor, ein Benutzer gibt als seinen Benutzernamen .* ein. Dies würde allen Benutzernamen entsprechen und ein Login ermöglichen, indem lediglich das Passwort eines Benutzers erraten wird.

5
Nick Kamer

Die beste Methode ist die Sprache Ihrer Wahl. Wenn Sie einen Modell-Wrapper für Ihre Objekte erstellen, durchlaufen Sie Ihre save () -Methode eine Reihe von Feldern, nach denen Sie suchen und die ebenfalls indiziert werden. Diese Gruppe von Feldern sollte aus Kleinbuchstaben bestehen, die dann für die Suche verwendet werden.

Jedes Mal, wenn das Objekt erneut gespeichert wird, werden die Kleinbuchstabeneigenschaften geprüft und mit Änderungen an den Haupteigenschaften aktualisiert. Auf diese Weise können Sie effizient suchen, jedoch die zusätzliche Arbeit ausblenden, die zum Aktualisieren der LC-Felder erforderlich ist.

Die Kleinbuchstabenfelder können ein Schlüssel sein: Wertobjektspeicher oder nur der Feldname mit dem Präfix lc_. Ich verwende die zweite, um das Abfragen zu vereinfachen (tiefe Objektabfragen können manchmal verwirrend sein). 

Hinweis: Sie möchten die lc_-Felder indizieren, nicht die Hauptfelder, auf denen sie basieren. 

5
RobKohr

Angenommen, Sie möchten in "Tabelle" nach "Spalte" suchen, und Sie möchten die Suche nach "Fall" aktivieren. Der beste und effizienteste Weg ist wie folgt;

//create empty JSON Object
mycolumn = {};

//check if column has valid value
if(column) {
    mycolumn.column = {$regex: new RegExp(column), $options: "i"};
}
Table.find(mycolumn);

Der obige Code fügt lediglich Ihren Suchwert als RegEx hinzu und sucht mit unempfindlichen Kriterien, die mit "Option" als Option festgelegt sind.

Alles Gute.

5
Ankur Soni
db.company_profile.find({ "companyName" : { "$regex" : "Nilesh" , "$options" : "i"}});
4
Nilesh

Der Aggregationsrahmen wurde in Mongodb 2.2 eingeführt. Sie können den Zeichenfolgenoperator "$ strcasecmp" verwenden, um einen Vergleich der Zeichenfolgen zwischen Groß- und Kleinschreibung zu machen. Es ist empfehlenswerter und einfacher als die Verwendung von Regex.

Hier ist das offizielle Dokument zum Aggregationsbefehlsoperator: https://docs.mongodb.com/manual/reference/operator/aggregation/strcasecmp/#exp._S_strcasecmp .

3
Jogue Wasin

Sie können case insensitive Indizes verwenden:

Im folgenden Beispiel wird eine Auflistung ohne Standardkollatierung erstellt und anschließend ein Index für das Namensfeld mit einer Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung hinzugefügt. 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 Standard-Kollatierung erstellen:

db.createCollection("users", { collation: { locale: 'tr', strength: 2 } } )
db.users.createIndex( { name : 1 } ) // inherits the default collation
2
Gencebay D.

Um eine Variable zu suchen und um sie zu umgehen:

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

Durch das Fluchen der Variablen wird die Abfrage vor Angriffen mit '. *' Oder anderen regulären Ausdrücken geschützt. 

escape-string-regexp

1
davidivad

Die Verwendung eines Filters funktioniert für mich in 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();

Es kann sogar den Index verwenden, weil ich glaube, dass die Methoden nach der Rückkehr aufgerufen werden, aber ich habe das noch nicht getestet.

Dies vermeidet auch ein Problem von 

var filter = Builders<Model>.Filter.Eq(p => p.Title.ToLower(), s.ToLower());

dass mongodb denken wird, dass p.Title.ToLower () eine Eigenschaft ist und nicht richtig zugeordnet werden kann.

1
A_Arnold

Verwenden Sie RegExp. Falls andere Optionen für Sie nicht funktionieren, ist RegExp eine gute Option. Die Groß- und Kleinschreibung wird dadurch nicht berücksichtigt.

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

verwenden Sie Benutzername in Abfragen, und dann ist es fertig.

Ich hoffe, es wird auch bei Ihnen funktionieren. Alles Gute.

0
Gouri Shankar

Wie Sie in mongo docs sehen können - seit Version 3.2 ist $text standardmäßig von der Groß- und Kleinschreibung abhängig: https://docs.mongodb.com/manual/core/index-text/#text-index-case-insensitivity

Erstellen Sie einen Textindex und verwenden Sie den $ text-Operator in Ihrer Abfrage .

0
avalanche1

Diese wurden für die Suche nach Zeichenketten getestet

{'_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
0
Ar maj

Ich war mit einem ähnlichen Problem konfrontiert und das hat bei mir funktioniert:

  const flavorExists = await Flavors.findOne({
    'flavor.name': { $regex: flavorName, $options: 'i' },
  });
0
Woppi

Für alle, die Golang verwenden und die case-sensitive Volltextsuche mit mongodb und der Bibliothek mgo godoc globalsign durchführen lassen möchten.

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


err := collection.Find(query).Collation(collation)
0
okandas

Ich habe eine einfache Funktion für die Regulierung "Groß- und Kleinschreibung" erstellt, die ich in meinem Filter verwende.

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

Dann filtern Sie einfach ein Feld wie folgt.

db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();
0
Nitesh