Vérifier si un champ contient une chaîne

454

Je cherche un opérateur, ce qui me permet de vérifier si la valeur d'un champ contient une certaine chaîne.

Quelque chose comme:

db.users.findOne({$contains:{"username":"son"}})

Est-ce possible?

johnny
la source

Réponses:

693

Vous pouvez le faire avec le code suivant.

db.users.findOne({"username" : {$regex : ".*son.*"}});
Parvin Gasimzade
la source
16
Notez que cela n'utilisera pas efficacement un index et entraînera l'analyse de toutes les valeurs pour les correspondances. Voir les notes sur les expressions régulières
Stennie
7
@Stennie, alors que proposez-vous pour utiliser efficacement l'index et trouver une sous-chaîne.
Blue Sky
4
@Vish: si votre cas d'utilisation courant est la recherche en texte libre d'un champ et que vous avez un grand nombre de documents, je voudrais symboliser le texte pour des requêtes plus efficaces. Vous pouvez utiliser des clés multiples pour une recherche simple en texte intégral, ou peut-être créer un index inversé en tant que collection distincte. Pour les recherches peu fréquentes ou une petite collection de documents, la numérisation de l'index complet peut être une performance acceptable (mais pas optimale).
Stennie
98
N'est-ce pas un peu exagéré? Ce que vous voulez, c'est db.users.findOne({"username" : {$regex : "son"}});
JamieJag
3
Pourrait vouloir vérifier la recherche en texte intégral dans Mongo 2.6
wprl
179

Comme le shell Mongo supporte les regex, c'est tout à fait possible.

db.users.findOne({"username" : /.*son.*/});

Si nous voulons que la requête soit insensible à la casse, nous pouvons utiliser l'option "i", comme indiqué ci-dessous:

db.users.findOne({"username" : /.*son.*/i});

Voir: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-RegularExpressions

James Gan
la source
1
Veuillez inclure un extrait de code illustrant l'utilisation d'expressions régulières pour la recherche. Les réponses devraient inclure plus d'informations qu'un simple lien ...
maerics
1
La réponse sélectionnée n'a pas fonctionné pour moi, mais celle-ci l'a fait (j'exécute des requêtes mongo via des commandes docker exec) Je pense que celle-ci devrait être la réponse sélectionnée car elle semble être plus polyvalente.
Arthur Weborg
5
comme les commentaires dans la réponse sélectionnée, je pense que cela db.users.findOne({"username" : /.*son.*/});pourrait aussi être exagéré et que l'expression /son/
régulière
2
Manière plus concise que d'utiliser $ regex
Lionet Chen
4
Modifiez ceci pour simplement l'utiliser{ username: /son/ }
Wyck
150

https://docs.mongodb.com/manual/reference/sql-comparison/

http://php.net/manual/en/mongo.sqltomongo.php

MySQL

SELECT * FROM users WHERE username LIKE "%Son%"

MongoDB

db.users.find({username:/Son/})
Zheng Kai
la source
8
Votre réponse MongoDB est bonne; pensez à modifier votre question pour supprimer les conseils MySQL non pertinents.
maerics
31
Supprimer toute la requête ou la changer? le plus connu de SQL, il est utile pour comprendre MongoDB
Zheng Kai
4
@ZhengKai: sur ce site, vous devez généralement répondre directement à la question, en utilisant uniquement les technologies spécifiques étiquetées et demandées.
maerics
98
@maerics personnellement, j'ai trouvé l'inclusion de Zheng de MySQL très utile car elle a fourni un point de référence.
Mike Bartlett
50
J'ai également trouvé la référence SQL pertinente, je pense qu'elle devrait rester.
vikingsteve
69

Depuis la version 2.4, vous pouvez créer un index de texte sur le ou les champs pour rechercher et utiliser l' opérateur $ text pour les requêtes.

Créez d'abord l'index:

db.users.createIndex( { "username": "text" } )

Ensuite, pour rechercher:

db.users.find( { $text: { $search: "son" } } )

Repères (~ 150 000 documents):

  • Regex (autres réponses) => 5,6-6,9 secondes
  • Recherche de texte => .164-.201 secondes

Remarques:

  • Une collection ne peut avoir qu'un seul index de texte. Vous pouvez utiliser un index de texte générique si vous souhaitez rechercher une zone de chaîne, comme ceci: db.collection.createIndex( { "$**": "text" } ).
  • Un index de texte peut être volumineux. Il contient une entrée d'index pour chaque mot post-racine unique dans chaque champ indexé pour chaque document inséré.
  • La construction d'un index de texte prendra plus de temps qu'un index normal.
  • Un index de texte ne stocke pas de phrases ou d'informations sur la proximité des mots dans les documents. Par conséquent, les requêtes de phrases s'exécuteront beaucoup plus efficacement lorsque toute la collection tient dans la RAM.
okoboko
la source
14
non, l'opérateur de texte infact ne permet pas d'exécuter "contient", donc il ne retournera que la correspondance exacte des mots, la seule option actuellement à partir de 3.0 est d'utiliser regex, c'est-à-dire db.users.find ({nom d'utilisateur: / son / i} ) celui-ci recherche chaque utilisateur contenant "son" (insensible à la casse)
comeGetSome
3
Devez-vous réindexer lorsque vous ajoutez ou supprimez des documents dans / de la collection?
Jake Wilson
Le titre de la question dit "contient". la recherche en texte intégral n'est pas applicable à la question.
Donato
29

Comme il s'agit de l'un des premiers résultats dans les moteurs de recherche et qu'aucun des éléments ci-dessus ne semble fonctionner pour MongoDB 3.x, voici une recherche d'expression régulière qui fonctionne:

db.users.find( { 'name' : { '$regex' : yourvalue, '$options' : 'i' } } )

Pas besoin de créer d'index supplémentaire ou similaire.

Nitai
la source
1
Les regex doivent être désinfectées.
sean
16

Voici ce que vous devez faire si vous connectez MongoDB via Python

db.users.find({"username": {'$regex' : '.*' + 'Son' + '.*'}})

vous pouvez également utiliser un nom de variable au lieu de «Son» et donc la concaténation de chaînes.

Patthebug
la source
dans es2015, vous pouvez utiliser des backticks {$ regex: .*${value}.*}
Michael Guild
16

Manière la plus simple d'accomplir cette tâche

Si vous souhaitez que la requête soit sensible à la casse

db.getCollection("users").find({'username':/Son/})

Si vous souhaitez que la requête ne respecte pas la casse

db.getCollection("users").find({'username':/Son/i})
Anurag Misra
la source
1
comment utiliser variable avec regex ??
Hisham
4

réponse idéale à son option d' indice d'utilisation i pour ne pas tenir compte de la casse

db.users.findOne({"username" : new RegExp(search_value, 'i') });
Hisham
la source
Les regex doivent être désinfectées.
sean
1

Comment ignorer les balises HTML dans une correspondance RegExp:

var text = '<p>The <b>tiger</b> (<i>Panthera tigris</i>) is the largest <a href="https://stackoverflow.com/wiki/Felidae" title="Felidae">cat</a> <a href="https://stackoverflow.com/wiki/Species" title="Species">species</a>, most recognizable for its pattern of dark vertical stripes on reddish-orange fur with a lighter underside. The species is classified in the genus <i><a href="https://stackoverflow.com/wiki/Panthera" title="Panthera">Panthera</a></i> with the <a href="https://stackoverflow.com/wiki/Lion" title="Lion">lion</a>, <a href="https://stackoverflow.com/wiki/Leopard" title="Leopard">leopard</a>, <a href="https://stackoverflow.com/wiki/Jaguar" title="Jaguar">jaguar</a>, and <a href="https://stackoverflow.com/wiki/Snow_leopard" title="Snow leopard">snow leopard</a>. It is an <a href="https://stackoverflow.com/wiki/Apex_predator" title="Apex predator">apex predator</a>, primarily preying on <a href="https://stackoverflow.com/wiki/Ungulate" title="Ungulate">ungulates</a> such as <a href="https://stackoverflow.com/wiki/Deer" title="Deer">deer</a> and <a href="https://stackoverflow.com/wiki/Bovid" class="mw-redirect" title="Bovid">bovids</a>.</p>';
var searchString = 'largest cat species';

var rx = '';
searchString.split(' ').forEach(e => {
  rx += '('+e+')((?:\\s*(?:<\/?\\w[^<>]*>)?\\s*)*)';
});

rx = new RegExp(rx, 'igm');

console.log(text.match(rx));

C'est probablement très facile à transformer en un filtre d'agrégation MongoDB.

Tamás Polgár
la source