Sélectionner

Description

Génère des documents, soit en référençant un sous-ensemble de champs existants, soit en attribuant un champ au résultat d'une expression donnée.

Exemples

Web

const result = await execute(db.pipeline()
  .collection("books")
  .select(field("soldBooks").multiply(field("price")).round().as("partialRevenue"))
  .aggregate(field("partialRevenue").sum().as("totalRevenue"))
  );
Swift
let result = try await db.pipeline()
  .collection("books")
  .select([Field("soldBooks").multiply(Field("price")).round().as("partialRevenue")])
  .aggregate([Field("partialRevenue").sum().as("totalRevenue")])
  .execute()

Kotlin

val result = db.pipeline()
    .collection("books")
    .select(Expression.multiply(field("soldBooks"), field("price")).round().alias("partialRevenue"))
    .aggregate(AggregateFunction.sum("partialRevenue").alias("totalRevenue"))
    .execute()

Java

Task<Pipeline.Snapshot> result = db.pipeline()
    .collection("books")
    .select(Expression.multiply(field("soldBooks"), field("price")).round().alias("partialRevenue"))
    .aggregate(AggregateFunction.sum("partialRevenue").alias("totalRevenue"))
    .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field

result = (
    client.pipeline()
    .collection("books")
    .select(
        Field.of("soldBooks")
        .multiply(Field.of("price"))
        .round()
        .as_("partialRevenue")
    )
    .aggregate(Field.of("partialRevenue").sum().as_("totalRevenue"))
    .execute()
)
Java
Pipeline.Snapshot result =
    firestore
        .pipeline()
        .collection("books")
        .select(round(multiply(field("soldBooks"), field("price"))).as("partialRevenue"))
        .aggregate(sum("partialRevenue").as("totalRevenue"))
        .execute()
        .get();
Accéder
snapshot := client.Pipeline().
	Collection("books").
	Select(firestore.Fields(
		firestore.Round(firestore.Multiply(firestore.FieldOf("soldBooks"), firestore.FieldOf("price"))).As("partialRevenue"),
	)).
	Aggregate(firestore.Accumulators(
		firestore.Sum("partialRevenue").As("totalRevenue"),
	)).
	Execute(ctx)

Comportement

Champs de métadonnées du document

L'étape select(...) n'émet que les champs ou expressions explicitement spécifiés dans l'étape. Il s'agit d'une divergence par rapport aux opérations principales, où le paramètre select(...) d'une requête sert de masque de propriété plutôt que de projection et inclut également toujours les champs de métadonnées du document __name__, __create_time__ et __update_time__.

Pour obtenir un comportement de type opérations Core dans un select(...), les champs doivent être spécifiés de manière explicite, comme suit :

Node.js

const results = await db.pipeline()
  .collection("/users")
  .select(
    field("__name__"),
    field("__create_time__"),
    field("__update_time__"),
    field("email"))
  .execute();

Position d'une étape de sélection

Il n'y a aucune restriction quant au moment où une étape de sélection peut être utilisée, mais tous les champs qui ne sont pas inclus dans une étape de sélection ne seront pas accessibles aux étapes suivantes d'un pipeline. Par exemple, pour sélectionner uniquement les champs name et location de toutes les villes du Canada à partir de l'ensemble de données suivant :

Node.js

await db.collection("cities").doc("SF").set({
  name: "San Francisco",
  population: 800000,
  location: {country: "USA", state: "California"}
});

await db.collection("cities").doc("TO").set({
  name: "Toronto",
  population: 3000000,
  location: {country: "Canada", province: "Ontario"}
});

Le pipeline suivant peut être utilisé :

Node.js

const names = await db.pipeline()
  .collection("/cities")
  .where(equal(field("location.country"), "Canada"))
  .select(stringConcat(field("name"), ", ", field("location.country")).as("name"), "population")
  .execute();

Cela génère les documents suivants :

{ name: "Toronto, Canada", population: 3000000 },

Toutefois, si l'étape select(...) est placée avant l'étape where(...), comme suit :

Node.js

const names = await db.pipeline()
  .collection("/cities")
  .select(stringConcat(field("name"), ",", field("location.country")).as("name"), "population")
  .where(equal(field("location.country"), "Canada"))
  .execute();

Aucun document ne sera produit, car location.country a été supprimé du document avant l'exécution de l'étape where(...).

Sélectionner les champs imbriqués

L'étape select(...) permet de sélectionner des champs imbriqués à partir de cartes et de tableaux. Par exemple, pour sélectionner le champ imbriqué country et la première entrée du tableau landmarks à partir des documents suivants :

Node.js

await db.collection("cities").doc("SF").set({
  name: "San Francisco",
  population: 800000,
  location: { country: "USA", state: "California" },
  landmarks: [ "Golden Gate Bridge", "Alcatraz" ]
});

await db.collection("cities").doc("TO").set({
  name: "Toronto",
  population:  3000000,
  province: "ON",
  location: { country: "Canada", province: "Ontario" },
  landmarks: [ "CN Tower", "Casa Loma" ]
});

await db.collection("cities").doc("AT").set({
  name: "Atlantis",
  population: null
});

Le pipeline suivant peut être utilisé :

Node.js

const locations = await db.pipeline()
  .collection("/cities")
  .select(
    field("name").as("city"),
    field("location.country").as("country"),
    field("landmarks").offset(0).as("topLandmark"))
  .execute();

Cela génère les documents suivants :

{ city: "San Francisco", country: "USA", topLandmark: "Golden Gate Bridge" },
{ city: "Toronto", country: "Canada", topLandmark: "CN Tower" },
{ city: "Atlantis" }

Si une valeur de tableau ou de mappage imbriquée n'existe pas, elle n'est pas incluse dans le document résultant. L'accès aux tableaux et aux cartes dans la phase de sélection se comporte de la même manière que les fonctions offset(...) et get_field(...), respectivement.

Attribuer des champs imbriqués

Le résultat d'une expression peut également être attribué à un champ imbriqué, ce qui permet à l'étape select(...) de renvoyer un sous-ensemble de champs imbriqués de l'étape précédente. Par exemple, les éléments suivants peuvent être utilisés pour s'assurer que seules les informations city et state sont renvoyées tout en conservant la forme d'origine du document :

Node.js

const results = await db.pipeline()
  .collection("/users")
  .addFields(
    field("__name__"),
    field("address.city").as("address.city"),
    field("address.state").as("address.state"))
  .execute();