web-dev-qa-db-fra.com

préfixe générique mongoDB: fulltext-search ($ text) recherche une partie avec chaîne de recherche

J'ai mongodb avec un $text-Index et des éléments comme celui-ci:

{
   foo: "my super cool item"
}
{
   foo: "your not so cool item"
}

Si je cherche avec 

mycoll.find({ $text: { $search: "super"} })

je reçois le premier article (correct).

Mais je veux aussi chercher avec "uper" pour obtenir le premier article - mais si j'essaye:

mycoll.find({ $text: { $search: "uper"} })

Je n'obtiens aucun résultat.

Ma question: S'il y a un moyen d'utiliser $ text pour qu'il trouve les résultats avec une partie de la chaîne de recherche? (par exemple, comme '%uper%' dans mysql)

Attention: je ne demande pas une recherche uniquement regex - je demande une recherche regex dans une recherche $ text!

40
mdunisch

Il n'est pas possible de le faire avec l'opérateur $text.

Les index de texte sont créés avec les termes inclus dans la valeur de chaîne ou dans un tableau de chaînes. La recherche est basée sur ces idexes.

Vous pouvez uniquement grouper des termes sur un livre sans en prendre partie.

Lire $text référence opérateur et description des index de texte .

42
francadaval

Ce que vous essayez de faire dans votre deuxième exemple est la recherche de préfixe avec caractères génériques dans votre collection mycoll sur le champ foo. Ce n’est pas une fonction pour laquelle la fonctionnalité de recherche de texte est conçue et il n’est pas possible de le faire avec l’opérateur $text. Ce comportement n'inclut pas la recherche de préfixe par un caractère générique sur un jeton donné dans le champ indexé. Cependant, vous pouvez également effectuer une recherche de regex comme suggéré par d'autres. Voici ma procédure pas à pas:

>db.mycoll.find()
{ "_id" : ObjectId("53add9364dfbffa0471c6e8e"), "foo" : "my super cool item" }
{ "_id" : ObjectId("53add9674dfbffa0471c6e8f"), "foo" : "your not so cool item" }
> db.mycoll.find({ $text: { $search: "super"} })
{ "_id" : ObjectId("53add9364dfbffa0471c6e8e"), "foo" : "my super cool item" }
> db.mycoll.count({ $text: { $search: "uper"} })
0

L'opérateur $text prend en charge la recherche d'un seul mot, la recherche d'un ou plusieurs mots ou la recherche d'une phrase. Le type de recherche que vous souhaitez n'est pas pris en charge 

La solution regex:

> db.mycoll.find({foo:/uper/})
{ "_id" : ObjectId("53add9364dfbffa0471c6e8e"), "foo" : "my super cool item" }
> 

La réponse à votre dernière question: pour faire le style mysql %super% dans mongoDB, vous devrez probablement faire:

db.mycoll.find( { foo : /.*super.*/ } );
12
user508434

Je n'ai pas assez de réputation pour commenter la solution de jasenkoh, mais c'est clairement la meilleure façon de gérer cette situation.

En situation d'OP, je voudrais:

db.mycoll.createIndex( { foo: "text" } )
db.mycoll.createIndex( { foo: 1 } )
db.mycoll.find({$or: [{$text: {$search: 'uper'}}, {foo: {$regex: 'uper'}}]})

Pour de meilleures performances (mais des résultats légèrement différents), remplacez la dernière ligne par:

db.mycoll.find({$or: [{$text: {$search: 'uper'}}, {foo: {$regex: '^uper'}}]})
5

Comme francadaval l'a dit, l'index de texte recherche par termes, mais si vous combinez regex et text-index, vous devriez être bon.

mycoll.find({$or: [ 
  { 
    $text: {
      $search: "super"
    }
  },
  {
    'column-name': {
      $regex: 'uper',
      $options: 'i'
  }
]})

Assurez-vous également que vous avez appliqué à la colonne un index normal autre que l'index de texte.

2
jasenkoh

Vous auriez pu réaliser est as-

db.mycoll.find( {foo: { $regex :  /uper/i  } })

Ici, "i" est une option, indique une recherche insensible à la casse

0
mohit_IBS