Présentation d'une requête avec filtres de plage et d'inégalité sur plusieurs propriétés

Firestore en mode Datastore permet d'utiliser des filtres de plage et d'inégalité sur plusieurs propriétés dans une seule requête. Vous pouvez désormais appliquer des conditions de plage et d'inégalité à plusieurs propriétés et simplifier le développement de votre application en déléguant la mise en œuvre de la logique de post-filtrage à Firestore en mode Datastore.

Filtres de plage et d'inégalité sur plusieurs propriétés

La requête suivante renvoie tous les utilisateurs dont l'âge est supérieur à 35 ans et dont la taille est comprise entre 60 et 70 ans, en utilisant des filtres de plage d'âge et de taille.

GQL

 SELECT * FROM /users WHERE age > 35 AND height > 60 AND height < 70;

Java


  Query<Entity> query =
    Query.newEntityQueryBuilder()
      .setKind("users")
      .setFilter(
        CompositeFilter.and(
            PropertyFilter.gt("age", 35), PropertyFilter.gt("height", 60), PropertyFilter.lt("height", 70)))
    .build();

Remarques sur l'indexation

Avant de commencer à exécuter des requêtes, assurez-vous d'avoir lu la documentation sur les requêtes.

Si aucune clause ORDER BY n'est spécifiée, Firestore en mode Datastore utilise n'importe quel index pouvant répondre à la condition de filtre de la requête pour la diffuser, produisant ainsi un ensemble de résultats ordonné en fonction de la définition de l'index.

Pour optimiser les performances et les coûts des requêtes Firestore en mode Datastore, vous devez optimiser l'ordre des propriétés dans l'index. Pour ce faire, assurez-vous que votre index est trié de gauche à droite de sorte que la requête soit distillée vers un ensemble de données, ce qui empêche l'analyse des entrées d'index superflues.

Supposons que vous souhaitiez effectuer une recherche dans une collection d'employés et trouver les employés dont le salaire est supérieur à 100 000 et dont le nombre d'années d'expérience est supérieur à 0. Grâce à votre compréhension de l'ensemble de données, vous savez que la contrainte salariale est plus sélective que la contrainte d'expérience. L'index (salary [...], experience [...]) idéal permettrait de réduire le nombre d'analyses d'index. Ainsi, la requête rapide et économique commande salary avant experience et se présente comme suit:

GQL

SELECT *
FROM /employees
WHERE salary > 100000 AND experience > 0
ORDER BY salary, experience

Java

Query<Entity> query =
  Query.newEntityQueryBuilder()
    .setKind("employees")
    .setFilter(
        CompositeFilter.and(
            PropertyFilter.gt("salary", 100000), PropertyFilter.gt("experience", 0)))
    .setOrderBy(OrderBy("salary"), OrderBy("experience"))
    .build();

Node.js

const query = datastore
  .createQuery("employees")
  .filter(
    and([
      new PropertyFilter("salary", ">", 100000),
      new PropertyFilter("experience", ">", 0),
       ])
    )
  .order("salary")
  .order("experience");

Python

query = client.query(kind="employees")
query.add_filter("salary", ">", 100000)
query.add_filter("experience", ">", 0)
query.order = ["-salary", "-experience"]

Bonnes pratiques pour optimiser les index

Lorsque vous optimisez des index, tenez compte des bonnes pratiques suivantes.

Classer les requêtes par égalité, puis par le champ de plage ou d'inégalité le plus sélectif

Firestore en mode Datastore utilise les propriétés les plus à gauche d'un index composite pour respecter les contraintes d'égalité et la contrainte de plage et d'inégalité, le cas échéant, sur le premier champ de la requête orderBy(). Ces contraintes peuvent réduire le nombre d'entrées d'index analysées par Firestore en mode Datastore. Firestore en mode Datastore utilise les propriétés restantes de l'index pour satisfaire aux autres contraintes de plage et d'inégalité de la requête. Ces contraintes ne réduisent pas le nombre d'entrées d'index analysées par Firestore en mode Datastore, mais filtrent les entités sans correspondance afin de réduire le nombre d'entités renvoyées aux clients.

Pour en savoir plus sur la création d'index efficaces, consultez Structure et définition des index et Optimiser des index.

Classer les propriétés par ordre décroissant de sélectivité des contraintes de requête

Pour vous assurer que Firestore en mode Datastore sélectionne l'index optimal pour votre requête, spécifiez une clause orderBy() qui ordonne les propriétés de plage et d'inégalité par ordre décroissant de sélectivité des contraintes de requête. Une sélectivité élevée correspond à un sous-ensemble plus restreint d'entités, tandis qu'une sélectivité plus faible correspond à un sous-ensemble plus vaste d'entités. Veillez à sélectionner des propriétés de plage et d'inégalité ayant une sélectivité plus élevée plus tôt dans l'ordre d'index que les propriétés présentant une faible sélectivité.

Pour réduire le nombre d'entités que Firestore en mode Datastore analyse et renvoie sur le réseau, vous devez toujours classer les propriétés dans l'ordre décroissant de la sélectivité de la contrainte de requête. Si l'ensemble de résultats n'est pas dans l'ordre requis et qu'il devrait être petit, vous pouvez implémenter une logique côté client pour le réorganiser conformément à vos attentes.

Par exemple, supposons que vous souhaitiez effectuer une recherche dans une collection d'employés pour trouver les employés dont le salaire est supérieur à 100 000 et classer les résultats par année d'expérience de l'employé. Si vous pensez que seul un petit nombre d'employés aura un salaire supérieur à 100 000, le moyen le plus efficace d'écrire la requête est le suivant:

Java

Query<Entity> query =
  Query.newEntityQueryBuilder()
    .setKind("employees")
    .setFilter(PropertyFilter.gt("salary", 100000))
    .setOrderBy(OrderBy("salary"))
    .build();
QueryResults<Entity> results = datastore.run(query);
// Order results by `experience`

Node.js

const query = datastore
  .createQuery("employees")
  .filter(new PropertyFilter("salary", ">", 100000))
  .order("salary");
const [entities] = await datastore.runQuery(query);
// Order results by `experience`

Python

query = client.query(kind="employees")
query.add_filter("salary", ">", 100000)
query.order = ["salary"]
results = query.fetch()
// Order results by `experience`

Bien que l'ajout d'un tri sur experience à la requête génère le même ensemble d'entités et évite de réorganiser les résultats sur les clients, la requête peut lire beaucoup plus d'entrées d'index superflues que la requête précédente. En effet, Firestore en mode Datastore privilégie toujours un index dont le préfixe de propriétés d'index correspond à la clause ordre par clause de la requête. Si des experience ont été ajoutés à la clause "classer par", Firestore en mode Datastore sélectionne l'index (experience [...], salary [...]) pour calculer les résultats de la requête. Comme il n'y a pas d'autres contraintes sur experience, Firestore en mode Datastore lit toutes les entrées d'index de la collection employees avant d'appliquer le filtre salary pour trouver l'ensemble de résultats final. Cela signifie que les entrées d'index qui ne satisfont pas au filtre salary sont toujours lues, ce qui augmente la latence et le coût de la requête.

Tarification

Les requêtes comportant des filtres de plage et d'inégalité sur plusieurs propriétés sont facturées en fonction des entités lues et des entrées d'index lues.

Pour en savoir plus, consultez la page Tarifs.

Limites

Outre les limites applicables aux requêtes, tenez compte des limites suivantes avant d'utiliser des requêtes avec des filtres de plage et d'inégalité sur plusieurs propriétés:

  • Firestore en mode Datastore limite le nombre d'opérateurs de plage ou d'inégalité à 10. Cela permet d'éviter que les requêtes deviennent trop coûteuses à exécuter.

Étape suivante