541 votes

Vérifier si un champ contient une chaîne de caractères

Je cherche un opérateur qui me permette 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 ?

852voto

parvin Points 8064

Vous pouvez le faire avec le code suivant.

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

21 votes

Notez que cela pas font un usage efficace d'un index et font que toutes les valeurs sont analysées pour trouver des correspondances. Voir les notes sur Expressions régulières

7 votes

@Stennie, alors que suggérez-vous pour utiliser efficacement l'index et trouver une sous-chaîne.

4 votes

@Vish : si votre cas d'utilisation courant est la recherche en texte libre d'un champ et que vous disposez d'un grand nombre de documents, je tokeniserais le texte pour des requêtes plus efficaces. Vous pourriez utiliser multikeys pour une simple recherche en texte intégral, ou peut-être construire une indice inversé comme une collection séparée. Pour les recherches peu fréquentes ou une petite collection de documents, le balayage de l'index complet peut constituer une performance acceptable (mais pas optimale).

196voto

James Gan Points 1834

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#Queries avancées-RegularExpressions

1 votes

Veuillez inclure un extrait de code démontrant l'utilisation des expressions régulières pour la recherche. Les réponses doivent inclure plus d'informations qu'un simple lien...

1 votes

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.

5 votes

Comme les commentaires dans la réponse choisie, je crois db.users.findOne({"username" : /.*son.*/}); pourrait aussi être exagéré et le regex pourrait simplement être /son/

184voto

Zheng Kai Points 716

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

9 votes

Votre réponse concernant MongoDB est bonne ; pensez à modifier votre question pour supprimer les conseils non pertinents concernant MySQL.

50 votes

Supprimer toute la requête ou la modifier ? La plupart des gens connaissent SQL, c'est utile pour comprendre MongoDB.

4 votes

@ZhengKai : sur ce site web, vous devez généralement répondre directement à la question, en utilisant uniquement les technologies spécifiques marquées et demandées.

82voto

okoboko Points 3834

A partir de la version 2.4, vous pouvez créer une indice de texte sur le(s) champ(s) à rechercher et utilisez la fonction Texte pour l'interrogation.

Tout d'abord, créez l'index :

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

Ensuite, pour chercher :

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

Benchmarks (~150K documents) :

  • Regex (autres réponses) => 5.6-6.9 secondes
  • Recherche de texte => .164-.201 secondes

Notes :

  • Une collection ne peut avoir qu'un seul index texte. Vous pouvez utiliser un index de texte avec caractère de remplacement si vous souhaitez effectuer une recherche dans les éléments suivants tout comme ceci : db.collection.createIndex( { "$**": "text" } ) .
  • Un index de texte peut être volumineux. Il contient une entrée d'index pour chaque mot unique post-séquencé dans chaque champ indexé pour chaque document inséré.
  • Un index textuel sera plus long à construire qu'un index normal.
  • Un index de texte ne stocke pas de phrases ni d'informations sur la proximité des mots dans les documents. Par conséquent, les requêtes de phrases s'exécutent beaucoup plus efficacement lorsque la collection entière tient dans la mémoire vive.

20 votes

Non, en fait l'opérateur de texte ne permet pas d'exécuter "contient", donc il ne retournera que des mots exacts, la seule option actuellement, à partir de la version 3.0, est d'utiliser une expression rationnelle, c'est-à-dire db.users.find( {username:/son/i } ) qui recherche tous les utilisateurs contenant "son" (cas-insensés).

3 votes

Devez-vous réindexer lorsque vous ajoutez ou supprimez des documents de la collection ?

0 votes

Le titre de la question dit "contient". La recherche en texte intégral n'est pas applicable à la question.

42voto

Nitai Points 740

Comme il s'agit de l'une des premières occurrences dans les moteurs de recherche, et qu'aucune des méthodes ci-dessus ne semble fonctionner pour MongoDB 3.x, voici une recherche regex qui fonctionne :

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

Il n'est pas nécessaire de créer un index supplémentaire ou autre.

1 votes

Les Regex doivent être nettoyés.

0 votes

Est venu de google et c'est le seul qui fonctionne pour moi. Dans la documentation, l'option i est pour "Insensibilité à la casse pour faire correspondre les majuscules et les minuscules".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X