Restrictions au niveau des requêtes

Cette page traite des restrictions liées à l'interrogation de données Datastore à partir de Google App Engine. La liste suivante répertorie les restrictions courantes que vous rencontrerez lors du développement pour Datastore.

Les entités sans propriété nommée dans la requête sont ignorées

Les entités du même genre ne doivent pas nécessairement avoir les mêmes propriétés. Pour être éligible en tant que résultat de requête, une entité doit posséder une valeur (éventuellement nulle) pour chaque propriété nommée dans les filtres et les ordres de tri de la requête. Sinon, l'entité est omise des index servant à exécuter la requête et, par conséquent, elle n'est pas incluse dans les résultats de la requête.

Filtrer les propriétés non indexées ne renvoie aucun résultat

Une requête ne peut pas trouver les valeurs de propriétés qui ne sont pas indexées ni effectuer de tri en fonction de ces propriétés. Consultez la page Index du datastore pour une présentation détaillée des propriétés non indexées.

Les filtres d'inégalité sont limités à une propriété au maximum

Pour éviter d'avoir à analyser l'intégralité de l'index, le mécanisme de requête repose sur le fait que tous les résultats potentiels d'une requête sont adjacents les uns aux autres dans l'index. Pour satisfaire à cette contrainte, une même requête ne peut pas utiliser de comparaisons d'inégalité (LESS_THAN, LESS_THAN_OR_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, NOT_EQUAL) sur plusieurs propriétés dans l'ensemble de ses filtres. Par exemple, la requête suivante est valide car les deux filtres d'inégalité s'appliquent à la même propriété :

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter birthYearMaxFilter =
    new FilterPredicate("birthYear", FilterOperator.LESS_THAN_OR_EQUAL, maxBirthYear);

Filter birthYearRangeFilter =
    CompositeFilterOperator.and(birthYearMinFilter, birthYearMaxFilter);

Query q = new Query("Person").setFilter(birthYearRangeFilter);

Cependant, la requête suivante n'est pas valide, car elle emploie des filtres d'inégalité sur deux propriétés différentes :

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter heightMaxFilter =
    new FilterPredicate("height", FilterOperator.LESS_THAN_OR_EQUAL, maxHeight);

Filter invalidFilter = CompositeFilterOperator.and(birthYearMinFilter, heightMaxFilter);

Query q = new Query("Person").setFilter(invalidFilter);

Sachez qu'une requête peut combiner des filtres d'égalité (EQUAL) pour différentes propriétés, ainsi qu'un ou plusieurs filtres d'inégalité sur une seule propriété. Par conséquent, l'exemple suivant est une requête valide :

Filter lastNameFilter = new FilterPredicate("lastName", FilterOperator.EQUAL, targetLastName);

Filter cityFilter = new FilterPredicate("city", FilterOperator.EQUAL, targetCity);

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter birthYearMaxFilter =
    new FilterPredicate("birthYear", FilterOperator.LESS_THAN_OR_EQUAL, maxBirthYear);

Filter validFilter =
    CompositeFilterOperator.and(
        lastNameFilter, cityFilter, birthYearMinFilter, birthYearMaxFilter);

Query q = new Query("Person").setFilter(validFilter);

Le tri des résultats de la requête n'est pas défini si aucun ordre de tri n'est spécifié

Lorsqu'une requête ne spécifie pas d'ordre de tri, les résultats sont renvoyés dans l'ordre dans lequel ils ont été récupérés. Cet ordre est susceptible d'être modifié à mesure que la mise en œuvre de Datastore évolue ou en cas de modification des index d'une application. Par conséquent, si l'application requiert des résultats de requête dans un ordre particulier, veillez à spécifier explicitement cet ordre de tri dans la requête.

Les ordres de tri sont ignorés sur les propriétés dotées de filtres d'égalité

Les requêtes qui incluent un filtre d'égalité pour une propriété donnée ignorent tout ordre de tri spécifié pour cette dernière. Il s'agit d'une simple optimisation permettant d'éviter un traitement inutile pour les propriétés à une seule valeur, dans la mesure où tous les résultats auront la même valeur pour la propriété, et aucun tri supplémentaire ne sera donc nécessaire. En revanche, les propriétés à valeurs multiples peuvent avoir des valeurs supplémentaires en plus de celle qui correspond au filtre d'égalité. Comme ce cas d'utilisation est rare, et que l'application d'un ordre de tri est coûteuse et nécessite des index supplémentaires, le planificateur de requêtes Datastore ignore simplement cet ordre de tri, même en cas de valeurs multiples. Cela peut entraîner le renvoi des résultats de la requête dans un ordre différent de celui que l'ordre de tri semble impliquer.

Les propriétés utilisées dans les filtres d'inégalité doivent être triées en premier

Pour récupérer tous les résultats correspondant à un filtre d'inégalité, une requête recherche dans l'index la première ligne correspondant au filtre, puis poursuit l'analyse jusqu'à ce qu'elle rencontre une ligne qui ne correspond pas. Pour que les lignes consécutives englobent l'intégralité de l'ensemble de résultats, elles doivent être triées en fonction de la propriété utilisée dans le filtre d'inégalité avant toute autre propriété. Ainsi, si une requête spécifie un ou plusieurs filtres d'inégalité avec un ou plusieurs ordres de tri, le premier ordre de tri doit faire référence à la propriété qui est nommée dans les filtres d'inégalité. Voici une requête valide :

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("birthYear", SortDirection.ASCENDING)
        .addSort("lastName", SortDirection.ASCENDING);

La requête suivante n'est pas valide, car elle n'effectue pas de tri en fonction de la propriété utilisée dans le filtre d'inégalité :

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

// Not valid. Missing sort on birthYear.
Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("lastName", SortDirection.ASCENDING);

De même, la requête suivante n'est pas valide, car la propriété utilisée dans le filtre d'inégalité n'est pas la première triée :

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

// Not valid. Sort on birthYear needs to be first.
Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("lastName", SortDirection.ASCENDING)
        .addSort("birthYear", SortDirection.ASCENDING);

Les propriétés possédant plusieurs valeurs peuvent se comporter de manière surprenante

En raison de la manière dont elles sont indexées, les entités possédant plusieurs valeurs pour la même propriété peuvent parfois interagir avec les filtres et les ordres de tri de la requête de manière inattendue et surprenante.

Si une requête comporte plusieurs filtres d'inégalité sur une propriété donnée, une entité ne correspond à la requête que si au moins l'une de ses valeurs individuelles pour la propriété satisfait tous les filtres. Par exemple, si une entité du genre Widget comporte les valeurs 1 et 2 pour la propriété x, elle ne correspond pas à la requête suivante :

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.GREATER_THAN, 1),
                new FilterPredicate("x", FilterOperator.LESS_THAN, 2)));

Chacune des valeurs x de l'entité satisfait à l'un des filtres, mais aucune valeur unique ne satisfait aux deux filtres. Notez que cela ne s'applique pas aux filtres d'égalité. Ainsi, cette même entité satisfera à la requête suivante :

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.EQUAL, 1),
                new FilterPredicate("x", FilterOperator.EQUAL, 2)));

Et ce, même si aucune des valeurs x individuelles de l'entité ne remplit les deux conditions de filtre.

L'opérateur NOT_EQUAL fonctionne comme un test "valeur différente de". Ainsi, par exemple, la requête

Query q = new Query("Widget").setFilter(new FilterPredicate("x", FilterOperator.NOT_EQUAL, 1));

correspond à toute entité Widget avec une valeur x différente de 1.

En Java, vous pouvez également utiliser une requête telle que

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.NOT_EQUAL, 1),
                new FilterPredicate("x", FilterOperator.NOT_EQUAL, 2)));

qui agit comme

x < 1 OR (x > 1 AND x < 2) OR x > 2

Ainsi, une entité Widget avec les valeurs x, 1, 2 et 3 correspond, mais une entité avec les valeurs 1 et 2 ne correspond pas.

De même, l'ordre de tri des propriétés à valeurs multiples est inhabituel. Étant donné que ces propriétés apparaissent une fois dans l'index pour chaque valeur unique, la première valeur affichée dans l'index détermine l'ordre de tri d'une entité.

  • Si les résultats de la requête sont triés par ordre croissant, le tri est effectué en fonction de la valeur la plus faible de la propriété.
  • Si les résultats sont triés par ordre décroissant, le tri est effectué en fonction de la valeur la plus élevée.
  • L'ordre de tri n'est pas affecté par les autres valeurs, ni par leur nombre.

Cela a pour conséquence inhabituelle qu'une entité dotée des valeurs de propriété 1 et 9 précède une entité possédant les valeurs 4, 5, 6 et 7 dans un tri par ordre croissant et décroissant.

Les requêtes au sein des transactions doivent inclure des filtres d'ancêtre

Les transactions Datastore n'opèrent que sur des entités appartenant au même groupe d'entités (descendant d'un ancêtre commun). Afin de conserver cette restriction, toutes les requêtes effectuées dans une transaction doivent inclure un filtre d'ancêtre qui spécifie un ancêtre dans le même groupe d'entités que les autres opérations de la transaction.