Wybierz

Opis

Generuje nowe dokumenty, odwołując się do podzbioru istniejących pól lub przypisując pole do wyniku danego wyrażenia.

Przykłady

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();
Go
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)

Zachowanie

Pola metadanych dokumentu

Etap select(...) emituje tylko pola lub wyrażenia wyraźnie określone na tym etapie. Jest to odmienne zachowanie niż w przypadku operacji podstawowych, w których ustawienie select(...) w zapytaniu działa jak maska właściwości, a nie projekcja, i zawsze obejmuje pola metadanych dokumentu __name__, __create_time__ i __update_time__.

Aby uzyskać zachowanie podobne do operacji podstawowych w select(...), pola muszą być wyraźnie określone, np.:

Node.js

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

Pozycja etapu Select

Nie ma ograniczeń co do tego, kiedy można użyć etapu Select, ale żadne pola nieobjęte etapem Select nie będą dostępne dla kolejnych etapów w potoku. Aby na przykład wybrać tylko pola name i location wszystkich miast w Kanadzie z tego zbioru danych:

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"}
});

Można użyć tego potoku:

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();

Który generuje te dokumenty:

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

Jeśli jednak etap select(...) zostanie umieszczony przed etapem where(...), np.:

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();

Nie zostaną wygenerowane żadne dokumenty, ponieważ location.country zostało usunięte z dokumentu przed wykonaniem etapu where(...).

Wybieranie pól zagnieżdżonych

Etap select(...) może służyć do wybierania pól zagnieżdżonych z map i tablic. Aby na przykład wybrać zagnieżdżone pole country i pierwszy wpis tablicy landmarks z tych dokumentów:

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
});

Można użyć tego potoku:

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();

Który generuje te dokumenty:

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

Jeśli zagnieżdżona wartość mapy lub tablicy nie istnieje, nie jest uwzględniana w dokumencie wynikowym. Dostęp do tablicy i mapy na etapie Select działa identycznie jak funkcje offset(...) i get_field(...), odpowiednio.

Przypisywanie pól zagnieżdżonych

Wynik wyrażenia można też przypisać do pola zagnieżdżonego, co umożliwia etapowi select(...) zwracanie podzbioru pól zagnieżdżonych z poprzedniego etapu. Na przykład można użyć tego, aby mieć pewność, że zwracane są tylko informacje city i state, przy jednoczesnym zachowaniu pierwotnego kształtu dokumentu:

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();