Requêtes de projection

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 Go 1.11

Lors de la préparation d'une requête (Query), spécifiez une projection à l'aide de la méthode Project :

q := datastore.NewQuery("People").Project("FirstName", "LastName")

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, ReadPath et DateWritten de toutes les entrées EventLog, triées par ordre croissant par DateWritten, et écrivent la valeur de chaque propriété dans le journal de l'application :

q := datastore.NewQuery("EventLog").
	Project("Title", "ReadPath", "DateWritten").
	Order("DateWritten")
t := q.Run(ctx)
for {
	var l EventLog
	_, err := t.Next(&l)
	if err == datastore.Done {
		break
	}
	if err != nil {
		log.Errorf(ctx, "Running query: %v", err)
		break
	}
	log.Infof(ctx, "Log record: %v, %v, %v", l.Title, l.ReadPath, l.DateWritten)
}

Regroupement(expérimental)

Les requêtes de projection peuvent utiliser la méthode 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.

q := datastore.NewQuery("Person").
	Project("LastName", "Height").Distinct().
	Filter("Height >", 20).
	Order("-Height").Order("LastName")

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 plus de 1 500 octets et les tableaux d'octets comportant plus de 1 500 éléments ne sont pas indexés.

  • 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é (=) 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.

    La requête renvoie des résultats qui ne sont que partiellement renseignés. Par conséquent, vous ne devez 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: []int{1, 1, 2, 3}, B: []string{"x", "y", "x"}}

La requête de projection suivante :

q := datastore.NewQuery("Foo").Project("A", "B").Filter("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.