Descrizione
Genera nuovi documenti facendo riferimento a un sottoinsieme di campi esistenti o assegnando un campo al risultato di una determinata espressione.
Esempi
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();
Vai
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)
Comportamento
Campi dei metadati dei documenti
La fase select(...) emette solo i campi o le espressioni specificati esplicitamente nella fase. Si tratta di una divergenza rispetto alle operazioni principali, in cui l'impostazione select(...) di una query funge da maschera di proprietà anziché da proiezione e include sempre anche i campi dei metadati del documento __name__, __create_time__ e __update_time__.
Per ottenere un comportamento in stile operazioni principali in un select(...), i campi devono essere specificati esplicitamente come segue:
Node.js
const results = await db.pipeline()
.collection("/users")
.select(
field("__name__"),
field("__create_time__"),
field("__update_time__"),
field("email"))
.execute();
Posizione di una fase di selezione
Non esistono restrizioni sull'utilizzo di una fase di selezione, ma i campi non inclusi in una fase di selezione non saranno accessibili alle fasi successive di una pipeline. Ad esempio, per selezionare solo i campi name e location di tutte le città del Canada dal seguente set di dati:
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"}
});
È possibile utilizzare la seguente pipeline:
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();
Che produce i seguenti documenti:
{ name: "Toronto, Canada", population: 3000000 },
Tuttavia, se la fase select(...) viene inserita prima della fase
where(...), come segue:
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();
Non verranno prodotti documenti, perché location.country è stato rimosso da
l documento prima dell'esecuzione della fase where(...).
Selezionare campi nidificati
La fase select(...) può essere utilizzata per selezionare i campi nidificati sia dalle mappe sia dagli array. Ad esempio, per selezionare il campo nidificato country e la prima voce dell'array landmarks dai seguenti documenti:
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
});
È possibile utilizzare la seguente pipeline:
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();
Che produce i seguenti documenti:
{ city: "San Francisco", country: "USA", topLandmark: "Golden Gate Bridge" },
{ city: "Toronto", country: "Canada", topLandmark: "CN Tower" },
{ city: "Atlantis" }
Se un valore di mappa nidificato o un valore di array non esiste, non viene incluso nel documento risultante. L'accesso ad array e mappe nella fase di selezione si comporta in modo identico
a offset(...) e get_field(...) funzioni,
rispettivamente.
Assegnare campi nidificati
Il risultato di un'espressione può essere assegnato anche a un campo nidificato, consentendo alla fase select(...) di restituire un sottoinsieme di campi nidificati dalla fase precedente. Ad esempio, è possibile utilizzare quanto segue per garantire che vengano restituite solo le informazioni su city e state, mantenendo al contempo la forma originale del documento:
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();