web-dev-qa-db-fra.com

Firestore de Google: Requête sur la sous-chaîne d'une valeur de propriété (recherche de texte)

Je cherche à ajouter un champ de recherche simple, j'aimerais utiliser quelque chose comme

collectionRef.where('name', 'contains', 'searchTerm')

J'ai essayé d'utiliser where('name', '==', '%searchTerm%'), mais cela ne m'a rien retourné.

69
tehfailsafe

Il n'y a pas d'opérateur de ce type, ceux autorisés sont ==, <, <=, >, >=.

Vous ne pouvez filtrer que par préfixes, par exemple pour tout ce qui commence entre bar et foo, vous pouvez utiliser

collectionRef.where('name', '>=', 'bar').where('name', '<=', 'foo')

Vous pouvez utiliser un service externe comme Algolia ou ElasticSearch pour cela.

21
Kuba

Bien que la réponse de Kuba soit vraie en ce qui concerne les restrictions, vous pouvez partiellement l'imiter avec une structure en ensembles:

{
  'terms': {
    'reebok': true,
    'mens': true,
    'tennis': true,
    'racket': true
  }
}

Maintenant, vous pouvez interroger avec

collectionRef.where('terms.tennis', '==', true)

Cela fonctionne car Firestore créera automatiquement un index pour chaque champ. Malheureusement, cela ne fonctionne pas directement pour les requêtes composées car Firestore ne crée pas automatiquement d'index composites.

Vous pouvez toujours contourner ce problème en stockant des combinaisons de mots, mais cela devient très vite moche.

Vous êtes probablement encore mieux avec un hors-bord recherche en texte intégral .

32
Gil Gilbert

Firebase ne prend pas explicitement en charge la recherche d'un terme dans une chaîne ...

Firebase prend toutefois en charge les éléments suivants, qui résoudront pour votre cas et bien d’autres:

Depuis août 2018, ils prennent en charge la requête array-contains. Voir: https://firebase.googleblog.com/2018/08/better-arrays-in-cloud-firestore.html

Vous pouvez maintenant définir tous vos termes clés dans un tableau en tant que champ, puis interroger tous les documents contenant un tableau contenant "X". Vous pouvez utiliser AND logique pour effectuer des comparaisons supplémentaires pour requêtes supplémentaires. (En effet, firebase ne prend actuellement pas en charge de manière native les requêtes composées pour plusieurs requêtes contenant un tableau les requêtes de tri 'AND' devront donc être effectuées côté client)

L'utilisation de tableaux dans ce style leur permettra d'être optimisés pour les écritures simultanées, ce qui est agréable! Je n'ai pas testé le support des requêtes batch (les documents ne le disent pas), mais je parierais que c'est une solution officielle.


Usage:

collection("collectionPath").
    where("searchTermsArray", "array-contains", "term").get()
13
Albert Renshaw

Conformément à Firestore docs , Cloud Firestore ne prend pas en charge l'indexation native ni la recherche de champs de texte dans les documents. De plus, le téléchargement d'une collection complète pour rechercher des champs côté client n'est pas pratique.

Les solutions de recherche tierces telles que Algolia et Elastic Search sont recommandées.

9
bholben

Réponse tardive, mais pour ceux qui cherchent encore une réponse, supposons que nous avons une collection d'utilisateurs et que dans chaque document de la collection, nous avons un champ "nom d'utilisateur", donc si vous voulez trouver un document dont le nom d'utilisateur commence par "al" nous pouvons faire quelque chose comme

 FirebaseFirestore.getInstance().collection("users").whereGreaterThanOrEqualTo("username", "al")
5
MoTahir

Je suis d’accord avec la réponse de @ Kuba, mais elle doit quand même ajouter un petit changement pour fonctionner parfaitement pour la recherche par préfixe. voici ce qui a fonctionné pour moi

Pour rechercher des notices commençant par le nom queryText

collectionRef.where('name', '>=', queryText).where('name', '<=', queryText+ '\uf8ff').

Le caractère \uf8ff utilisé dans la requête est un point de code très élevé dans la plage Unicode (il s'agit d'un code de zone d'utilisation privée [PUA]). Comme c'est après la plupart des caractères normaux dans Unicode, la requête correspond à toutes les valeurs commençant par queryText.

3
Ankit Prajapati

Je viens d'avoir ce problème et proposé une solution assez simple.

String search = "ca";
Firestore.instance.collection("categories").orderBy("name").where("name",isGreaterThanOrEqualTo: search).where("name",isLessThanOrEqualTo: search+"z")

IsGreaterThanOrEqualTo nous permet de filtrer le début de notre recherche et en ajoutant un "z" à la fin de la valeur isLessThanOrEqualTo afin de limiter notre recherche à un autre point.

2
Jacob Bonk

Si vous ne souhaitez pas utiliser un service tiers comme Algolia, les services fonctions cloud de Firebase constituent une excellente alternative. Vous pouvez créer une fonction pouvant recevoir un paramètre d'entrée, traiter via les enregistrements côté serveur, puis renvoyer ceux qui correspondent à vos critères.

1
Rap

En fait, je pense que la meilleure solution dans Firestore consiste à placer toutes les sous-chaînes dans un tableau et à effectuer une requête array_contains. Cela vous permet de faire une correspondance de sous-chaîne. Un peu exagéré pour stocker toutes les sous-chaînes, mais si vos termes de recherche sont courts, c'est très très raisonnable.

1
Dan Fein