MongoDB: Est-il possible de faire une requête insensible à la casse?

Exemple:

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

Vous pouvez utiliser une regex .

Dans votre exemple, ce serait:

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

Je dois dire, cependant, que vous pourriez peut-être simplement baisser la valeur (ou augmenter) la valeur en cours de route plutôt que de supporter le coût supplémentaire chaque fois que vous le trouvez. Évidemment, cela ne fonctionnera pas pour les noms de personnes et autres, mais peut-être comme des balises.

METTRE À JOUR:

La réponse originale est maintenant obsolète. Mongodb prend désormais en charge la recherche avancée en texte intégral, avec de nombreuses fonctionnalités.

RÉPONSE ORIGINALE:

Il convient de noter que la recherche avec insensible à la casse de regex / i signifie que mongodb ne peut pas effectuer de recherche par index, de sorte que les requêtes sur de grands ensembles de données peuvent prendre beaucoup de temps.

Même avec de petits ensembles de données, ce n’est pas très efficace. Vous prenez un coup de processeur beaucoup plus important que vos mandats de requête, ce qui pourrait devenir un problème si vous essayez d’atteindre une échelle.

Comme alternative, vous pouvez stocker une copie en majuscule et la rechercher. Par exemple, j’ai une table utilisateur qui a un nom d’utilisateur qui est une casse mixte, mais l’id est une copie majuscule du nom d’utilisateur. Cela garantit que la duplication sensible à la casse est impossible (avoir à la fois “Foo” et “foo” ne sera pas autorisé), et je peux rechercher par id = username.toUpperCase () pour obtenir une recherche insensible à la casse.

Si votre champ est volumineux, tel qu’un corps de message, la duplication des données n’est probablement pas une bonne option. Je pense que l’utilisation d’un indexeur externe comme Apache Lucene est la meilleure option dans ce cas.

Gardez à l’esprit que l’exemple précédent:

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

fera que chaque entrée contenant la barre corresponde à la requête (bar1, barxyz, openbar), cela pourrait être très dangereux pour une recherche de nom d’utilisateur sur une fonction d’authentification …

Vous devrez peut-être faire correspondre uniquement le terme de recherche en utilisant la syntaxe d’expressions rationnelle appropriée:

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

Voir http://www.regular-expressions.info/ pour obtenir de l’aide sur la syntaxe des expressions régulières

Si vous avez besoin de créer l’expression rationnelle à partir d’une variable, cette méthode est bien meilleure: https://stackoverflow.com/a/10728069/309514

Vous pouvez alors faire quelque chose comme:

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

Cela présente l’avantage d’être plus programmatique ou de gagner en performance en la compilant à l’avance si vous la réutilisez beaucoup.

A partir de Mongodb 3.4, vous devez utiliser un index de classement insensible à la casse. C’est le moyen le plus rapide d’effectuer une recherche insensible à la casse sur des jeux de données de taille de plus en plus grande. J’ai personnellement envoyé un email à l’un des fondateurs pour qu’il fonctionne, et il l’a fait! (C’était un problème sur JIRA depuis 5 ans, et beaucoup ont demandé la fonctionnalité). Voici comment cela fonctionne:

Un index insensible à la casse est créé en spécifiant un classement de 1 ou 2. Vous pouvez créer un index insensible à la casse comme ceci:

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

Ou vous pouvez le faire pour toute la collection par défaut lorsque vous créez la firebase database comme suit:

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

Et l’utiliser comme ça:

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

Cela rendra “New York”, “New York”, etc.

Vous pouvez également faire en sorte que tous les index utilisent un classement par défaut lorsque vous créez la collection comme ceci:

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

L’avantage de cette méthode est une efficacité et une rapidité nettement accrues sur des ensembles de données plus importants.

Pour plus d’informations: 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

Manière correcte de le faire en Mongo

Ne pas utiliser RegExp

Aller naturel Et utiliser l’indexation intégrée de mongodb, rechercher

Étape 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 } ] ) 

Étape 2 :

Besoin de créer un index sur le champ de texte que vous souhaitez rechercher, sans indexer la requête sera extrêmement lente

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

étape 3 :

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

Mongo (version actuelle 2.0.0) n’autorise pas les recherches non sensibles à la casse sur les champs indexés – voir leur documentation . Pour les champs non indexés, les expressions régulières répertoriées dans les autres réponses devraient convenir.

En utilisant Mongoose cela a fonctionné pour moi:

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

La meilleure méthode consiste à choisir la langue de votre choix. Lorsque vous créez un wrapper de modèle pour vos objects, votre méthode save () doit parcourir un ensemble de champs que vous allez rechercher et qui sont également indexés. ces ensembles de champs doivent avoir des contreparties minuscules qui sont ensuite utilisées pour la recherche.

Chaque fois que l’object est enregistré à nouveau, les propriétés en minuscules sont ensuite vérifiées et mises à jour avec les modifications apscopes aux propriétés principales. Cela vous permettra de rechercher efficacement, mais masquez le travail supplémentaire nécessaire pour mettre à jour les champs lc à chaque fois.

Les champs en minuscules peuvent être une clé: valeur object magasin ou juste le nom du champ avec un préfixe lc_. J’utilise le second pour simplifier les requêtes (l’interrogation profonde des objects peut parfois être source de confusion).

Note: vous voulez indexer les champs lc_, pas les champs principaux dont ils sont basés.

Supposons que vous vouliez rechercher “colonne” dans “Table” et que vous souhaitiez une recherche insidieuse. Le moyen le meilleur et le plus efficace est le suivant;

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

Le code ci-dessus ajoute simplement votre valeur de recherche en tant que RegEx et recherche avec des critères insensibles définis avec l’option “i”.

Bonne chance.

Une chose très importante à garder à l’esprit lorsque vous utilisez une requête basée sur Regex – Lorsque vous faites cela pour un système de connexion, échappez à chaque caractère que vous recherchez et n’oubliez pas les opérateurs ^ et $. Lodash a une fonction intéressante pour cela , si vous l’utilisez déjà:

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

Pourquoi? Imaginez un utilisateur saisissant .* Comme nom d’utilisateur. Cela correspondrait à tous les noms d’utilisateur, permettant une connexion en devinant simplement le mot de passe d’un utilisateur.

Le framework d’agrégation a été introduit dans mongodb 2.2. Vous pouvez utiliser l’opérateur de chaîne “$ strcasecmp” pour effectuer une comparaison insensible à la casse entre les chaînes. C’est plus recommandé et plus facile que d’utiliser regex.

Voici le document officiel sur l’opérateur de commande d’agrégation: https://docs.mongodb.com/manual/reference/operator/aggregation/strcasecmp/#exp._S_strcasecmp .

Utiliser un filtre fonctionne pour moi en C #.

 ssortingng s = "searchTerm"; var filter = Builders.Filter.Where(p => p.Title.ToLower().Contains(s.ToLower())); var listSorted = collection.Find(filter).ToList(); var list = collection.Find(filter).ToList(); 

Il peut même utiliser l’index car je pense que les méthodes sont appelées après le retour, mais je ne l’ai pas encore testé.

Cela évite également un problème de

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

Ce mongodb pensera que p.Title.ToLower () est une propriété et ne correspondra pas correctement.

Vous pouvez utiliser des index insensibles à la casse :

L’exemple suivant crée une collection sans classement par défaut, puis ajoute un index sur le champ de nom avec un classement insensible à la casse. Composants internationaux pour 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 } } ) 

Pour utiliser l’index, les requêtes doivent spécifier le même classement.

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

ou vous pouvez créer une collection avec le classement par défaut:

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

Pour rechercher une variable et y échapper:

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

Echapper à la variable protège la requête contre les attaques avec ‘. *’ Ou une autre regex.

chaîne-d’échappement-regexp

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

J’ai créé un simple Func pour l’expression régulière insensible à la casse que j’utilise dans mon filtre.

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

Ensuite, il vous suffit de filtrer sur un champ comme suit.

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

Comme vous pouvez le voir dans la documentation de mongo – depuis la version 3.2, $text index de $text est insensible à la casse par défaut: https://docs.mongodb.com/manual/core/index-text/#text-index-case-insensitivity

Créez un index de texte et utilisez l’opérateur $ text dans votre requête .

Ceux-ci ont été testés pour les recherches de chaînes

 {'_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 

J’avais fait face à un problème similaire et c’est ce qui a fonctionné pour moi:

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

Utilisez RegExp , Si d’autres options ne fonctionnent pas pour vous, RegExp est une bonne option. Cela rend la chaîne sensible à la casse.

 var username = "John"; var uname = new RegExp(username, "i"); 

La valeur de uname sera comme /John/i .

utiliser uname dans les requêtes au lieu du nom d’utilisateur, puis c’est terminé.

J’espère que cela fonctionnera pour vous aussi. Bonne chance.