Une note à tous ceux qui essaieront d'utiliser une réponse impliquant des expressions régulières: les expressions régulières doivent être nettoyées.
sean
Réponses:
126
La solution de Chris Fulstow fonctionnera (+1), cependant, elle peut ne pas être efficace, surtout si votre collection est très grande. Les expressions régulières non enracinées (celles qui ne commencent pas par ^, qui ancrent l'expression régulière au début de la chaîne) et celles qui utilisent l' iindicateur d'insensibilité à la casse n'utiliseront pas d'index, même s'ils existent.
Une autre option que vous pourriez envisager est de dénormaliser vos données pour stocker une version minuscule du namechamp, par exemple sous la forme name_lower. Vous pouvez ensuite interroger cela efficacement (surtout s'il est indexé) pour les correspondances exactes insensibles à la casse comme:
Excellente réponse, mon approche regex ralentit vraiment une fois qu'elle doit numériser quelques millions de documents.
Chris Fulstow
34
Ce n'est en fait pas tout à fait correct, car vous pourriez trouver "Andrew quelque chose" en recherchant "Andrew". Ajustez donc l'expression régulière sur: new RegExp('^'+ username + '$', "i")pour être une correspondance exacte.
Tarion
9
Selon le site Web de MongoDB, toute expression régulière insensible à la casse n'est pas efficace pour l'index "$ regex ne peut utiliser un index efficacement que lorsque l'expression régulière a une ancre pour le début (c'est-à-dire ^) d'une chaîne et est une correspondance sensible à la casse "
Ryan Schumacher
2
Avec Mongoose, cela a fonctionné pour moi: User.find ({'username': {$ regex: new RegExp ('^' + username.toLowerCase (), 'i')}}, function (err, res) {if (err ) throw err; next (null, res);});
ChrisRich
5
N'oubliez jamais d'échapper le nom lorsque vous travaillez avec des expressions régulières. Nous ne voulons pas que les injections prennent le dessus sur la beauté de mongodb. Imaginez simplement que vous avez utilisé ce code pour une page de connexion et que le nom d'utilisateur était ".*".
Tobias
90
Vous auriez besoin d'utiliser une expression régulière insensible à la casse pour celui-ci, par exemple
MongoDB 3.4 inclut désormais la possibilité de créer un véritable index insensible à la casse, ce qui augmentera considérablement la vitesse des recherches insensibles à la casse sur de grands ensembles de données. Il est fait en spécifiant un classement avec une force de 2.
Le moyen le plus simple de le faire est probablement de définir un classement dans la base de données. Ensuite, toutes les requêtes héritent de ce classement et l'utiliseront:
Les deux lignes sont insensibles à la casse. L'e-mail dans la base de données pourrait être [email protected]et les deux lignes trouveront toujours l'objet dans la base de données.
La sensibilité à la casse et la sensibilité diacritique sont définies sur false par défaut lors des requêtes de cette manière.
Vous pouvez même développer cela en sélectionnant les champs dont vous avez besoin à partir de l'objet utilisateur d'Andrew en procédant de cette manière:
Les expressions régulières sont plus lentes que la correspondance de chaîne littérale. Cependant, un champ minuscule supplémentaire augmentera la complexité de votre code. En cas de doute, utilisez des expressions régulières. Je suggérerais de n'utiliser un champ explicitement minuscule que s'il peut remplacer votre champ, c'est-à-dire que vous ne vous souciez pas du cas en premier lieu.
Notez que vous devrez échapper le nom avant regex. Si vous voulez des caractères génériques saisis par l'utilisateur, préférez les ajouter .replace(/%/g, '.*')après l'échappement afin de pouvoir faire correspondre "a%" pour trouver tous les noms commençant par "a".
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:
Réponses:
La solution de Chris Fulstow fonctionnera (+1), cependant, elle peut ne pas être efficace, surtout si votre collection est très grande. Les expressions régulières non enracinées (celles qui ne commencent pas par
^
, qui ancrent l'expression régulière au début de la chaîne) et celles qui utilisent l'i
indicateur d'insensibilité à la casse n'utiliseront pas d'index, même s'ils existent.Une autre option que vous pourriez envisager est de dénormaliser vos données pour stocker une version minuscule du
name
champ, par exemple sous la formename_lower
. Vous pouvez ensuite interroger cela efficacement (surtout s'il est indexé) pour les correspondances exactes insensibles à la casse comme:db.collection.find({"name_lower": thename.toLowerCase()})
Ou avec une correspondance de préfixe (une expression régulière enracinée) comme:
db.collection.find( {"name_lower": { $regex: new RegExp("^" + thename.toLowerCase(), "i") } } );
Ces deux requêtes utiliseront un index sur
name_lower
.la source
new RegExp('^'+ username + '$', "i")
pour être une correspondance exacte.".*"
.Vous auriez besoin d'utiliser une expression régulière insensible à la casse pour celui-ci, par exemple
db.collection.find( { "name" : { $regex : /Andrew/i } } );
Pour utiliser le modèle d'expression régulière de votre
thename
variable, construisez un nouvel objet RegExp :var thename = "Andrew"; db.collection.find( { "name" : { $regex : new RegExp(thename, "i") } } );
Mise à jour: pour une correspondance exacte, vous devez utiliser l'expression régulière
"name": /^Andrew$/i
. Merci à Yannick L.la source
name
, pas seulement égal.{ "name": /^Andrew$/i }
Je l'ai résolu comme ça.
var thename = 'Andrew'; db.collection.find({'name': {'$regex': thename,$options:'i'}});
Si vous souhaitez interroger sur la «correspondance exacte insensible à la casse», vous pouvez procéder comme suit.
var thename = '^Andrew$'; db.collection.find({'name': {'$regex': thename,$options:'i'}});
la source
MongoDB 3.4 inclut désormais la possibilité de créer un véritable index insensible à la casse, ce qui augmentera considérablement la vitesse des recherches insensibles à la casse sur de grands ensembles de données. Il est fait en spécifiant un classement avec une force de 2.
Le moyen le plus simple de le faire est probablement de définir un classement dans la base de données. Ensuite, toutes les requêtes héritent de ce classement et l'utiliseront:
db.createCollection("cities", { collation: { locale: 'en_US', strength: 2 } } ) db.names.createIndex( { city: 1 } ) // inherits the default collation
Vous pouvez également le faire comme ceci:
db.myCollection.createIndex({city: 1}, {collation: {locale: "en", strength: 2}});
Et utilisez-le comme ceci:
db.myCollection.find({city: "new york"}).collation({locale: "en", strength: 2});
Cela renverra les villes nommées «New York», «New York», «New York», etc.
Pour plus d'informations: https://jira.mongodb.org/browse/SERVER-90
la source
Avec Mongoose (et Node), cela a fonctionné:
User.find({ email: /^[email protected]$/i })
User.find({ email: new RegExp(
`^ $ {emailVariable} $`, 'i')})Dans MongoDB, cela a fonctionné:
db.users.find({ email: { $regex: /^[email protected]$/i }})
Les deux lignes sont insensibles à la casse. L'e-mail dans la base de données pourrait être
[email protected]
et les deux lignes trouveront toujours l'objet dans la base de données.De même, nous pourrions utiliser
/^[email protected]$/i
et il trouverait toujours des e-mails:[email protected]
dans la base de données.la source
Pour trouver une chaîne insensible à la casse, utilisez ceci,
var thename = "Andrew"; db.collection.find({"name":/^thename$/i})
la source
Je viens de résoudre ce problème il y a quelques heures.
var thename = 'Andrew' db.collection.find({ $text: { $search: thename } });
Vous pouvez même développer cela en sélectionnant les champs dont vous avez besoin à partir de l'objet utilisateur d'Andrew en procédant de cette manière:
db.collection.find({ $text: { $search: thename } }).select('age height weight');
Référence: https://docs.mongodb.org/manual/reference/operator/query/text/#text
la source
... avec mangouste sur NodeJS qui interroge:
const countryName = req.params.country; { 'country': new RegExp(`^${countryName}$`, 'i') };
ou
const countryName = req.params.country; { 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } }; // ^australia$
ou
const countryName = req.params.country; { 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } }; // ^turkey$
Un exemple de code complet en Javascript, NodeJS avec Mongoose ORM sur 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); }); });
la source
La requête suivante trouvera les documents avec la chaîne requise de manière insensible et avec une occurrence globale également
db.collection.find({name:{ $regex: new RegExp(thename, "ig") } },function(err, doc) { //Your code here... });
la source
Pour rechercher une chaîne littérale insensible à la casse:
Utilisation de regex (recommandé)
db.collection.find({ name: { $regex: new RegExp('^' + name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '$', 'i') } });
Utilisation de l'index minuscule (plus rapide)
db.collection.find({ name_lower: name.toLowerCase() });
Les expressions régulières sont plus lentes que la correspondance de chaîne littérale. Cependant, un champ minuscule supplémentaire augmentera la complexité de votre code. En cas de doute, utilisez des expressions régulières. Je suggérerais de n'utiliser un champ explicitement minuscule que s'il peut remplacer votre champ, c'est-à-dire que vous ne vous souciez pas du cas en premier lieu.
Notez que vous devrez échapper le nom avant regex. Si vous voulez des caractères génériques saisis par l'utilisateur, préférez les ajouter
.replace(/%/g, '.*')
après l'échappement afin de pouvoir faire correspondre "a%" pour trouver tous les noms commençant par "a".la source
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
la source
Un moyen simple serait d'utiliser $ toLower comme ci-dessous.
db.users.aggregate([ { $project: { name: { $toLower: "$name" } } }, { $match: { name: the_name_to_search } } ])
la source