Requêtes de projection

Remarque : Les développeurs qui créent des applications sont vivement encouragés à utiliser la bibliothèque cliente NDB qui présente plusieurs avantages supplémentaires par rapport à cette bibliothèque cliente, tels que la mise en cache automatique des entités via l'API Memcache. Si vous utilisez actuellement l'ancienne bibliothèque cliente DB, consultez le guide de migration de DB vers NDB.

La plupart des requêtes Datastore renvoient des résultats comprenant des entités entières, mais bien souvent une application ne s'intéresse en réalité qu'à quelques propriétés d'une entité. Les requêtes de projection vous permettent de n'exécuter des requêtes Datastore que sur les propriétés spécifiques d'une entité dont vous avez réellement besoin, ce qui entraîne une latence et un coût inférieurs à ceux induits par la récupération de l'entité entière.

Les requêtes de projection sont semblables aux requêtes SQL de ce type :

SELECT name, email, phone FROM CUSTOMER

Vous pouvez employer toutes les fonctionnalités de filtrage et de tri disponibles pour les requêtes d'entité standards, conformément aux limites décrites ci-après. La requête renvoie des résultats partiels, seules les valeurs des propriétés spécifiées (name, email et phone dans l'exemple) étant indiquées. Toutes les autres propriétés ne sont pas renseignées.

Utiliser des requêtes de projection dans Python

Vous spécifiez une projection comme suit : les requêtes de projection sont prises en charge par les objets Query et GqlQuery. Les deux classes nécessitent cette importation :

from google.appengine.ext import db

Vous spécifiez une projection comme suit :

proj = db.Query(entity_name, projection=('property_1', 'property_2','property_n'))

proj = db.GqlQuery("SELECT property_1, property_2, property_n FROM entity_name")

Vous gérez les résultats de ces requêtes comme vous le feriez pour une requête d'entité standard, par exemple, en effectuant une itération sur les résultats.

Les exemples de requêtes suivants interrogent les propriétés title, read_path et date_written de toutes les entrées EventLog, triées par ordre croissant par date_written, et écrivent la valeur de chaque propriété dans le journal de l'application :

for proj in db.GqlQuery("SELECT title, read_path, date_written" +
                        "FROM EventLog" +
                        "ORDER BY date_written ASC"):
  logging.info(proj.title)
  logging.info(proj.read_path)
  logging.info(proj.date_written)

Regroupement(expérimental)

Les requêtes de projection peuvent utiliser le mot clé distinct pour garantir que seuls des résultats totalement uniques seront renvoyés dans un ensemble de résultats. Cette méthode permet de ne renvoyer que le premier résultat des entités dont les valeurs des propriétés en cours de projection sont identiques.

query = db.Query(projection=['A', 'B'], distinct=True).filter('B >', 1).order('-B, A')

Limites relatives aux projections

Les requêtes de projection sont soumises aux restrictions suivantes :

  • Seules les propriétés indexées peuvent être projetées.

    La projection n'est pas compatible avec les propriétés non indexées, explicitement ou implicitement. Les chaînes de texte longues (Text) et les chaînes d'octets longues (Blob) ne sont pas indexées.

  • Une même propriété ne peut pas être projetée plusieurs fois.

  • Les propriétés référencées dans un filtre d'égalité (=) ou d'appartenance (IN) ne peuvent pas être projetées.

    Exemple :

    SELECT A FROM kind WHERE B = 1
    

    est une requête valide (propriété projetée non utilisée dans le filtre d'égalité), de même que :

    SELECT A FROM kind WHERE A > 1
    

    (pas un filtre d'égalité). Par contre :

    SELECT A FROM kind WHERE A = 1
    

    (propriété projetée utilisée dans un filtre d'égalité) n'est pas une requête valide.

  • Les résultats renvoyés par une requête de projection ne doivent pas être réenregistrés dans Datastore.

    Étant donné que la requête renvoie des résultats qui ne sont que partiellement renseignés, vous ne pouvez pas les réécrire dans Datastore.

Projections et propriétés dotées de plusieurs valeurs

La projection d'une propriété dotée de plusieurs valeurs n'insère pas toutes les valeurs de cette propriété. Au lieu de cela, une entité distincte est renvoyée pour chaque combinaison unique de valeurs projetées correspondant à la requête. Par exemple, supposons que vous ayez une entité de genre Foo dotée de deux propriétés ayant plusieurs valeurs, A et B :

entity = Foo(A=[1, 1, 2, 3], B=['x', 'y', 'x'])

La requête de projection suivante :

SELECT A, B FROM Foo WHERE A < 3

renvoie quatre entités avec les combinaisons de valeurs suivantes :

A = 1, B = 'x'
A = 1, B = 'y'
A = 2, B = 'x'
A = 2, B = 'y'

Notez que si une entité possède une propriété à valeurs multiples sans valeur, aucune entrée ne sera incluse dans l'index et une requête de projection incluant cette propriété ne renverra aucun résultat pour cette entité.

Index des projections

Les requêtes de projection exigent que toutes les propriétés spécifiées dans la projection soient incluses dans un index Datastore. Le serveur de développement App Engine génère automatiquement les index dont vous avez besoin dans le fichier de configuration d'index, index.yaml, qui est importé avec votre application.

Une manière de réduire le nombre d'index requis consiste à projeter les mêmes propriétés de façon systématique, même si elles ne sont pas toutes toujours nécessaires. Par exemple, ces requêtes nécessitent deux index distincts :

SELECT A, B FROM Kind
SELECT A, B, C FROM Kind

Toutefois, si vous projetez toujours les propriétés A, B et C, même lorsque la propriété C n'est pas requise, un seul index suffit.

La conversion d'une requête existante en une requête de projection peut nécessiter la création d'un index si les propriétés de la projection ne sont pas déjà incluses dans une autre partie de la requête. Par exemple, supposons que vous ayez la requête existante suivante :

SELECT * FROM Kind WHERE A > 1 ORDER BY A, B

qui nécessite l'index suivant :

Index(Kind, A, B)

Si vous convertissez la requête en l'une de ces requêtes de projection,

SELECT C FROM Kind WHERE A > 1 ORDER BY A, B
SELECT A, B, C FROM Kind WHERE A > 1 ORDER BY A, B

vous obtenez une nouvelle propriété (C), ce qui nécessite la création d'un index Index(Kind, A, B, C). Notez que la requête de projection suivante :

SELECT A, B FROM Kind WHERE A > 1 ORDER BY A, B

ne modifie pas l'index requis, car les propriétés projetées A et B étaient déjà incluses dans la requête existante.