Hintergrund
Pipelinevorgänge bieten eine neue Abfrageschnittstelle für Cloud Firestore, die erweiterte Abfragefunktionen und komplexe Ausdrücke unterstützt. Es werden viele neue Funktionen eingeführt, darunter min(...), max(...), substring(...), regex_match(...) und array_contains_all(...), sowie Phasen, um komplexe Transformationen durchführen zu können.
Einstieg
Anleitungen zum Installieren und Initialisieren von Client-SDKs finden Sie in den folgenden Leitfäden:
Syntax
In den folgenden Abschnitten finden Sie eine Übersicht über die Syntax für Pipelinevorgänge.
Konzepte
Ein wesentlicher Unterschied bei Pipelinevorgängen ist die Einführung einer expliziten „Phasen“-Reihenfolge. So können komplexere Abfragen formuliert werden. Es ist jedoch eine bemerkenswerte Abweichung von der vorhandenen Abfrageschnittstelle mit Core-Vorgängen, bei denen die Reihenfolge der Phasen impliziert wurde. Betrachten Sie das folgende Beispiel für Pipelinevorgänge:
Web
const pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort(field("name").ascending()) // Step 4: Return the top 10. Note applying the limit earlier in the // pipeline would have unintentional results. .limit(10);
Swift
let pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(Field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort([Field("name").ascending()]) // Step 4: Return the top 10. Note applying the limit earlier in the pipeline would have // unintentional results. .limit(10)
Kotlin
val pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort(field("name").ascending()) // Step 4: Return the top 10. Note applying the limit earlier in the pipeline would have // unintentional results. .limit(10)
Java
Pipeline pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort(field("name").ascending()) // Step 4: Return the top 10. Note applying the limit earlier in the pipeline would have // unintentional results. .limit(10);
Python
from google.cloud.firestore_v1.pipeline_expressions import Field pipeline = ( client.pipeline() .collection("cities") .where(Field.of("population").greater_than(100_000)) .sort(Field.of("name").ascending()) .limit(10) )
Go
pipeline := client.Pipeline(). Collection("cities"). Where(firestore.FieldOf("population").GreaterThan(100000)). Sort(firestore.Orders(firestore.Ascending(firestore.FieldOf("name")))). Limit(10)
Initialisierung
Pipelinevorgänge haben eine sehr vertraute Syntax, die von vorhandenen Cloud Firestore-Abfragen stammt. Zuerst initialisieren Sie eine Abfrage, indem Sie Folgendes schreiben:
Web
const { getFirestore } = require("firebase/firestore"); const { execute } = require("firebase/firestore/pipelines"); const database = getFirestore(app, "enterprise"); const pipeline = database.pipeline();
Swift
let firestore = Firestore.firestore(database: "enterprise") let pipeline = firestore.pipeline()
Kotlin
val firestore = Firebase.firestore("enterprise") val pipeline = firestore.pipeline()
Java
FirebaseFirestore firestore = FirebaseFirestore.getInstance("enterprise"); PipelineSource pipeline = firestore.pipeline();
Python
firestore_client = firestore.client(default_app, "your-new-enterprise-database") pipeline = firestore_client.pipeline()
Go
client, err := firestore.NewClientWithDatabase(ctx, projectID, databaseID) if err != nil { fmt.Fprintf(w, "firestore.NewClientWithDatabase failed: %v", err) return err } defer client.Close() pipeline := client.Pipeline().Collection("books")
Struktur
Beim Erstellen von Pipelinevorgängen sind einige Begriffe wichtig: Phasen, Ausdrücke und Funktionen sowie Unterabfrage-Wrapper.

Phasen: Eine Pipeline kann aus einer oder mehreren Phasen bestehen. Logisch gesehen stellen diese die Reihe von Schritten (oder Phasen) dar, die zum Ausführen der Abfrage ausgeführt werden.
Ausdrücke: Phasen akzeptieren häufig einen Ausdruck, mit dem Sie komplexere Abfragen formulieren können. Der Ausdruck kann einfach sein und aus einer einzelnen Funktion wie eq("a", 1) bestehen. Sie können auch komplexere Ausdrücke formulieren, indem Sie Ausdrücke wie and(eq("a", 1), eq("b", 2)). verschachteln.
Unterabfrage-Wrapper: Mit Funktionen wie array() und scalar() können Sie eine verschachtelte Pipeline als Ausdruck in eine Phase einbetten.
Felder / Konstanten / Variablen
Pipelinevorgänge unterstützen komplexe Ausdrücke. Daher ist es wichtig, zu unterscheiden, ob ein Wert ein Feld, eine Konstante oder eine Variable darstellt.
Während sich Felder auf Daten in Dokumenten beziehen und Konstanten die Angabe eines beliebigen Werts als Argument für einen Ausdruck ermöglichen, können Sie mit Variablen temporäre Werte definieren und verwenden, die auf die Abfrageausführung und nicht auf die verarbeiteten Dokumente beschränkt sind. Im Folgenden finden Sie eine Übersicht über diese Konzepte. Weitere Informationen zum Lesen und Schreiben von Variablen während der Abfrageausführung finden Sie in der Phase let(...).
| Felder | Konstanten | Variablen | |
|---|---|---|---|
| Purpose | auf Felder in Dokumenten zugreifen oder sie darin speichern | einen festen Wert angeben | Temporäre Werte während der Pipelineausführung verwenden |
| SDK-Nutzung | field("name") |
constant("val") |
variable("name") |
| Einsatzbereich | lokal für das aktuelle Dokument | global | Global für Pipeline und Unterpipelines |
| Undefined Reference | wird mit absent ausgewertet |
– | generiert Laufzeitfehler |
Beispiele:
Web
const pipeline = db.pipeline() .collection("cities") .where(field("name").equal(constant("Toronto")));
Swift
let pipeline = db.pipeline() .collection("cities") .where(Field("name").equal(Constant("Toronto")))
Kotlin
val pipeline = db.pipeline() .collection("cities") .where(field("name").equal(constant("Toronto")))
Java
Pipeline pipeline = db.pipeline() .collection("cities") .where(field("name").equal(constant("Toronto")));
Python
from google.cloud.firestore_v1.pipeline_expressions import Field, Constant pipeline = ( client.pipeline() .collection("cities") .where(Field.of("name").equal(Constant.of("Toronto"))) )
Go
pipeline := client.Pipeline().Collection("cities"). Where(firestore.FieldOf("name").Equal(firestore.ConstantOf("Toronto")))
Phasen
Eingabephasen
Die Eingabephase ist die erste Phase einer Abfrage. Sie definiert die anfängliche Gruppe von Dokumenten, die Sie abfragen. Bei Pipeline-Vorgängen ähnelt dies weitgehend vorhandenen Abfragen, bei denen die meisten Abfragen entweder mit einer collection(...)- oder einer collection_group(...)-Phase beginnen. Zwei neue Eingabephasen sind database() und documents(...), wobei database() die Rückgabe aller Dokumente in der Datenbank ermöglicht, während documents(...) identisch mit einem Batch-Lesevorgang ist.
Web
let results; // Return all restaurants in San Francisco results = await execute(db.pipeline().collection("cities/sf/restaurants")); // Return all restaurants results = await execute(db.pipeline().collectionGroup("restaurants")); // Return all documents across all collections in the database (the entire database) results = await execute(db.pipeline().database()); // Batch read of 3 documents results = await execute(db.pipeline().documents([ doc(db, "cities", "SF"), doc(db, "cities", "DC"), doc(db, "cities", "NY") ]));
Swift
var results: Pipeline.Snapshot // Return all restaurants in San Francisco results = try await db.pipeline().collection("cities/sf/restaurants").execute() // Return all restaurants results = try await db.pipeline().collectionGroup("restaurants").execute() // Return all documents across all collections in the database (the entire database) results = try await db.pipeline().database().execute() // Batch read of 3 documents results = try await db.pipeline().documents([ db.collection("cities").document("SF"), db.collection("cities").document("DC"), db.collection("cities").document("NY") ]).execute()
Kotlin
var results: Task<Pipeline.Snapshot> // Return all restaurants in San Francisco results = db.pipeline().collection("cities/sf/restaurants").execute() // Return all restaurants results = db.pipeline().collectionGroup("restaurants").execute() // Return all documents across all collections in the database (the entire database) results = db.pipeline().database().execute() // Batch read of 3 documents results = db.pipeline().documents( db.collection("cities").document("SF"), db.collection("cities").document("DC"), db.collection("cities").document("NY") ).execute()
Java
Task<Pipeline.Snapshot> results; // Return all restaurants in San Francisco results = db.pipeline().collection("cities/sf/restaurants").execute(); // Return all restaurants results = db.pipeline().collectionGroup("restaurants").execute(); // Return all documents across all collections in the database (the entire database) results = db.pipeline().database().execute(); // Batch read of 3 documents results = db.pipeline().documents( db.collection("cities").document("SF"), db.collection("cities").document("DC"), db.collection("cities").document("NY") ).execute();
Python
# Return all restaurants in San Francisco results = client.pipeline().collection("cities/sf/restaurants").execute() # Return all restaurants results = client.pipeline().collection_group("restaurants").execute() # Return all documents across all collections in the database (the entire database) results = client.pipeline().database().execute() # Batch read of 3 documents results = ( client.pipeline() .documents( client.collection("cities").document("SF"), client.collection("cities").document("DC"), client.collection("cities").document("NY"), ) .execute() )
Go
// Return all restaurants in San Francisco results1, err := client.Pipeline().Collection("cities/sf/restaurants").Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err } // Return all restaurants results2, err := client.Pipeline().CollectionGroup("restaurants").Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err } // Return all documents across all collections in the database (the entire database) results3, err := client.Pipeline().Database().Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err } // Batch read of 3 documents results4, err := client.Pipeline(). Documents([]*firestore.DocumentRef{ client.Collection("cities").Doc("SF"), client.Collection("cities").Doc("DC"), client.Collection("cities").Doc("NY"), }). Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err }
Wie bei allen anderen Phasen ist die Reihenfolge der Ergebnisse aus diesen Eingabephasen nicht stabil. Wenn eine bestimmte Reihenfolge erforderlich ist, sollte immer ein sort(...)-Operator hinzugefügt werden.
WHERE
Die Phase where(...) fungiert als Standardfiltervorgang für Dokumente, die in der vorherigen Phase generiert wurden, und spiegelt größtenteils die vorhandene „where“-Syntax für vorhandene Abfragen wider. Alle Dokumente, bei denen ein bestimmter Ausdruck zu einem Wert ungleich true ausgewertet wird, werden aus den zurückgegebenen Dokumenten herausgefiltert.
Mehrere where(...)-Anweisungen können miteinander verkettet werden und als and(...)-Ausdruck fungieren. Die folgenden beiden Abfragen sind beispielsweise logisch äquivalent und können synonym verwendet werden.
Web
let results; results = await execute(db.pipeline().collection("books") .where(field("rating").equal(5)) .where(field("published").lessThan(1900)) ); results = await execute(db.pipeline().collection("books") .where(and(field("rating").equal(5), field("published").lessThan(1900))) );
Swift
var results: Pipeline.Snapshot results = try await db.pipeline().collection("books") .where(Field("rating").equal(5)) .where(Field("published").lessThan(1900)) .execute() results = try await db.pipeline().collection("books") .where(Field("rating").equal(5) && Field("published").lessThan(1900)) .execute()
Kotlin
var results: Task<Pipeline.Snapshot> results = db.pipeline().collection("books") .where(field("rating").equal(5)) .where(field("published").lessThan(1900)) .execute() results = db.pipeline().collection("books") .where(Expression.and(field("rating").equal(5), field("published").lessThan(1900))) .execute()
Java
Task<Pipeline.Snapshot> results; results = db.pipeline().collection("books") .where(field("rating").equal(5)) .where(field("published").lessThan(1900)) .execute(); results = db.pipeline().collection("books") .where(Expression.and( field("rating").equal(5), field("published").lessThan(1900) )) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import And, Field results = ( client.pipeline() .collection("books") .where(Field.of("rating").equal(5)) .where(Field.of("published").less_than(1900)) .execute() ) results = ( client.pipeline() .collection("books") .where(And(Field.of("rating").equal(5), Field.of("published").less_than(1900))) .execute() )
Go
results1, err := client.Pipeline(). Collection("books"). Where(firestore.FieldOf("rating").Equal(5)). Where(firestore.FieldOf("published").LessThan(1900)). Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err } results2, err := client.Pipeline(). Collection("books"). Where(firestore.And( firestore.FieldOf("rating").Equal(5), firestore.FieldOf("published").LessThan(1900), )). Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err }
Felder auswählen / hinzufügen und entfernen
Mit select(...), add_fields(...) und remove_fields(...) können Sie die Felder ändern, die von einer vorherigen Phase zurückgegeben werden. Diese drei werden im Allgemeinen als Projektionsphasen bezeichnet.
Mit select(...) und add_fields(...) können Sie das Ergebnis eines Ausdrucks einem vom Nutzer angegebenen Feldnamen zuweisen. select(...) gibt nur die Dokumente mit den angegebenen Feldnamen zurück, während add_fields(...) das Schema der vorherigen Phase erweitert (und möglicherweise Werte mit identischen Feldnamen überschreibt).
Mit remove_fields(...) können Sie eine Reihe von Feldern angeben, die aus der vorherigen Phase entfernt werden sollen. Die Angabe nicht vorhandener Feldnamen ist ein No-Op.
Weitere Informationen finden Sie im Abschnitt Zurückzugebende Felder einschränken unten. Im Allgemeinen ist es jedoch hilfreich, eine solche Phase zu verwenden, um das Ergebnis auf die im Client benötigten Felder zu beschränken. So lassen sich die Kosten und die Latenz für die meisten Abfragen reduzieren.
Aggregiert / eindeutig
In der Phase aggregate(...) können Sie eine Reihe von Aggregationen für die Eingabedokumente ausführen. Standardmäßig werden alle Dokumente zusammengefasst. Sie können jedoch ein optionales grouping-Argument angeben, um die Eingabedokumente in verschiedenen Buckets zusammenzufassen.
Web
const results = await execute(db.pipeline() .collection("books") .aggregate( field("rating").average().as("avg_rating") ) .distinct(field("genre")) );
Swift
let results = try await db.pipeline() .collection("books") .aggregate([ Field("rating").average().as("avg_rating") ], groups: [ Field("genre") ]) .execute()
Kotlin
val results = db.pipeline() .collection("books") .aggregate( AggregateStage .withAccumulators(AggregateFunction.average("rating").alias("avg_rating")) .withGroups(field("genre")) ) .execute()
Java
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .aggregate(AggregateStage .withAccumulators( AggregateFunction.average("rating").alias("avg_rating")) .withGroups(field("genre"))) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .aggregate( Field.of("rating").average().as_("avg_rating"), groups=[Field.of("genre")] ) .execute() )
Go
snapshot := client.Pipeline(). Collection("books"). Aggregate( firestore.Accumulators(firestore.Average("rating").As("avg_rating")), firestore.WithAggregateGroups("genre"), ). Execute(ctx)
Wenn groupings nicht angegeben ist, wird in dieser Phase nur ein einzelnes Dokument erstellt. Andernfalls wird für jede eindeutige Kombination von groupings-Werten ein Dokument generiert.
Die Phase distinct(...) ist ein vereinfachter Aggregationsoperator, mit dem nur die eindeutigen groupings ohne Akkumulatoren generiert werden können. In allen anderen Belangen verhält es sich identisch mit aggregate(...). Das folgende Beispiel zeigt:
Web
const results = await execute(db.pipeline() .collection("books") .distinct( field("author").toUpper().as("author"), field("genre") ) );
Swift
let results = try await db.pipeline() .collection("books") .distinct([ Field("author").toUpper().as("author"), Field("genre") ]) .execute()
Kotlin
val results = db.pipeline() .collection("books") .distinct( field("author").toUpper().alias("author"), field("genre") ) .execute()
Java
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .distinct( field("author").toUpper().alias("author"), field("genre") ) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .distinct(Field.of("author").to_upper().as_("author"), "genre") .execute() )
Go
snapshot := client.Pipeline(). Collection("books"). Distinct(firestore.Fields( firestore.ToUpper(firestore.FieldOf("author")).As("author"), firestore.FieldOf("genre"), )). Execute(ctx)
Funktionen
Funktionen sind ein Baustein zum Erstellen von Ausdrücken und komplexen Abfragen. Eine vollständige Liste der Funktionen mit Beispielen finden Sie in der Funktionsreferenz. Zur Erinnerung: Hier ist die Struktur einer typischen Abfrage:

Viele Phasen akzeptieren Ausdrücke, die eine oder mehrere Funktionen enthalten. Die häufigste Verwendung von Funktionen findet sich in den Phasen where(...) und select(...). Es gibt zwei Haupttypen von Funktionen, mit denen Sie vertraut sein sollten:
Web
let results; // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = await execute(db.pipeline().collection("books") .select(field("current").logicalMinimum(field("updated")).as("price_min")) ); // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = await execute(db.pipeline().collection("books") .aggregate(field("price").minimum().as("min_price")) );
Swift
var results: Pipeline.Snapshot // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = try await db.pipeline().collection("books") .select([ Field("current").logicalMinimum(["updated"]).as("price_min") ]) .execute() // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = try await db.pipeline().collection("books") .aggregate([Field("price").minimum().as("min_price")]) .execute()
Kotlin
var results: Task<Pipeline.Snapshot> // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = db.pipeline().collection("books") .select( field("current").logicalMinimum("updated").alias("price_min") ) .execute() // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = db.pipeline().collection("books") .aggregate(AggregateFunction.minimum("price").alias("min_price")) .execute()
Java
Task<Pipeline.Snapshot> results; // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = db.pipeline().collection("books") .select( field("current").logicalMinimum("updated").alias("price_min") ) .execute(); // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = db.pipeline().collection("books") .aggregate(AggregateFunction.minimum("price").alias("min_price")) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field # Type 1: Scalar (for use in non-aggregation stages) # Example: Return the min store price for each book. results = ( client.pipeline() .collection("books") .select( Field.of("current").logical_minimum(Field.of("updated")).as_("price_min") ) .execute() ) # Type 2: Aggregation (for use in aggregate stages) # Example: Return the min price of all books. results = ( client.pipeline() .collection("books") .aggregate(Field.of("price").minimum().as_("min_price")) .execute() )
Go
// Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results1, err := client.Pipeline(). Collection("books"). Select(firestore.Fields( firestore.LogicalMinimum(firestore.FieldOf("current"), firestore.FieldOf("updated")).As("price_min"), )). Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err } // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results2, err := client.Pipeline(). Collection("books"). Aggregate(firestore.Accumulators( firestore.Minimum("price").As("min_price"), )). Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err }
Limits
In der Enterprise-Version gibt es im Allgemeinen keine Einschränkungen für die Form der Abfrage. Mit anderen Worten: Sie sind nicht auf eine kleine Anzahl von Werten in einer IN- oder OR-Abfrage beschränkt. Stattdessen gibt es zwei primäre Limits, die Sie beachten sollten:
- Frist: 60 Sekunden (identisch mit der Standard-Version).
- Arbeitsspeichernutzung: Limit von 128 MiB für die Menge der materialisierten Daten während der Abfrageausführung.
Fehler
Fehlgeschlagene Abfragen können verschiedene Ursachen haben. Hier finden Sie einen Link zu häufigen Fehlern und den entsprechenden Maßnahmen, die Sie ergreifen können:
| Fehlercode | Aktion |
DEADLINE_EXCEEDED
|
Die von Ihnen ausgeführte Abfrage überschreitet ein Zeitlimit von 60 Sekunden und erfordert eine zusätzliche Optimierung. Tipps finden Sie im Abschnitt zur Leistung. Wenn Sie die Ursache des Problems nicht ermitteln können, wenden Sie sich an das Team. |
RESOURCE_EXHAUSTED
|
Die von Ihnen ausgeführte Abfrage überschreitet die Speicherlimits und erfordert eine zusätzliche Optimierung. Tipps finden Sie im Abschnitt zur Leistung. Wenn Sie die Ursache des Problems nicht ermitteln können, wenden Sie sich an das Team. |
INTERNAL
|
Wenden Sie sich an das Team, um Unterstützung zu erhalten. |
Leistung
Für Datenbanken der Enterprise-Version ist nicht immer ein Index erforderlich.
Das bedeutet, dass eine Abfrage eine höhere Latenz aufweisen kann als vorhandene Abfragen, die sofort mit dem Fehler FAILED_PRECONDITION (fehlender Index) fehlgeschlagen wären. Es gibt einige Schritte, die Sie unternehmen können, um die Leistung von Pipeline-Vorgängen zu verbessern.
Indexe erstellen
Verwendeter Index
Mit Query Explain können Sie feststellen, ob Ihre Abfrage von einem Index bedient wird oder auf einen weniger effizienten Vorgang wie einen Tabellenscan zurückgreift. Wenn Ihre Abfrage nicht vollständig über einen Index ausgeführt wird, können Sie einen Index erstellen. Folgen Sie dazu der Anleitung.
Indexe erstellen
Sie können der vorhandenen Dokumentation zur Indexverwaltung folgen, um Indexe zu erstellen. Bevor Sie einen Index erstellen, sollten Sie sich mit den allgemeinen Best Practices für Indexe in Cloud Firestore vertraut machen. Damit Ihre Abfrage Indexe nutzen kann, sollten Sie die Best Practices befolgen, um Indexe mit Feldern in der folgenden Reihenfolge zu erstellen:
- Alle Felder, die in Gleichheitsfiltern verwendet werden (in beliebiger Reihenfolge)
- Alle Felder, nach denen sortiert wird (in derselben Reihenfolge)
- Felder, die in Bereichs- oder Ungleichheitsfiltern verwendet werden, in absteigender Reihenfolge der Selektivität der Abfrageeinschränkung
Beispiel für die folgende Abfrage:
Web
const results = await execute(db.pipeline() .collection("books") .where(field("published").lessThan(1900)) .where(field("genre").equal("Science Fiction")) .where(field("rating").greaterThan(4.3)) .sort(field("published").descending()) );
Swift
let results = try await db.pipeline() .collection("books") .where(Field("published").lessThan(1900)) .where(Field("genre").equal("Science Fiction")) .where(Field("rating").greaterThan(4.3)) .sort([Field("published").descending()]) .execute()
Kotlin
val results = db.pipeline() .collection("books") .where(field("published").lessThan(1900)) .where(field("genre").equal("Science Fiction")) .where(field("rating").greaterThan(4.3)) .sort(field("published").descending()) .execute()
Java
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .where(field("published").lessThan(1900)) .where(field("genre").equal("Science Fiction")) .where(field("rating").greaterThan(4.3)) .sort(field("published").descending()) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .where(Field.of("published").less_than(1900)) .where(Field.of("genre").equal("Science Fiction")) .where(Field.of("rating").greater_than(4.3)) .sort(Field.of("published").descending()) .execute() )
Go
snapshot := client.Pipeline(). Collection("books"). Where(firestore.FieldOf("published").LessThan(1900)). Where(firestore.FieldOf("genre").Equal("Science Fiction")). Where(firestore.FieldOf("rating").GreaterThan(4.3)). Sort(firestore.Orders(firestore.Descending(firestore.FieldOf("published")))). Execute(ctx)
Der empfohlene Index ist ein Index mit Sammlungsbereich für books für (genre [...], published DESC, avg_rating DESC).
Indexdichte
Cloud Firestore unterstützt dünnbesetzte und nicht dünnbesetzte Indexe. Weitere Informationen finden Sie unter Indexdichte.
Abgedeckte Abfragen und sekundäre Indexe
Cloud Firestore kann das Abrufen des vollständigen Dokuments überspringen und nur Ergebnisse aus dem Index zurückgeben, wenn alle zurückgegebenen Felder in einem sekundären Index vorhanden sind. Dies führt in der Regel zu einer erheblichen Verbesserung der Latenz (und der Kosten). Verwenden Sie die folgende Beispielabfrage:
Web
const results = await execute(db.pipeline() .collection("books") .where(field("category").like("%fantasy%")) .where(field("title").exists()) .where(field("author").exists()) .select(field("title"), field("author")) );
Swift
let results = try await db.pipeline() .collection("books") .where(Field("category").like("%fantasy%")) .where(Field("title").exists()) .where(Field("author").exists()) .select([Field("title"), Field("author")]) .execute()
Kotlin
val results = db.pipeline() .collection("books") .where(field("category").like("%fantasy%")) .where(field("title").exists()) .where(field("author").exists()) .select(field("title"), field("author")) .execute()
Java
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .where(field("category").like("%fantasy%")) .where(field("title").exists()) .where(field("author").exists()) .select(field("title"), field("author")) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .where(Field.of("category").like("%fantasy%")) .where(Field.of("title").exists()) .where(Field.of("author").exists()) .select("title", "author") .execute() )
Go
snapshot := client.Pipeline(). Collection("books"). Where(firestore.FieldOf("category").Like("%fantasy%")). Where(firestore.FieldOf("title").FieldExists()). Where(firestore.FieldOf("author").FieldExists()). Select(firestore.Fields("title", "author")). Execute(ctx)
Wenn die Datenbank bereits einen Index für den Sammlungsbereich für books für (category [...], title [...], author [...]) hat, muss nichts aus den Hauptdokumenten selbst abgerufen werden. In diesem Fall spielt die Reihenfolge im Index keine Rolle. Dies wird durch [...] angegeben.
Zurückzugebende Felder einschränken
Standardmäßig gibt eine Cloud Firestore-Abfrage alle Felder in einem Dokument zurück, analog zu einem SELECT * in relationalen Systemen. Wenn Ihre Anwendung jedoch nur einen Teil der Felder benötigt, können Sie die Phasen select(...) oder restrict(...) verwenden, um diese Filterung serverseitig durchzuführen. Dadurch wird sowohl die Antwortgröße (und damit die Kosten für ausgehenden Netzwerktraffic) als auch die Latenz verringert.
Tools zur Fehlerbehebung
Query Explain
Mit Query Explain können Sie Ausführungsmesswerte und Details zu den verwendeten Indexen sichtbar machen.
Messwerte
Pipelinevorgänge sind vollständig in vorhandene Cloud Firestore-Messwerte eingebunden.
Bekannte Probleme / Einschränkungen
Spezialisierte Indexe
Pipelinevorgänge unterstützen noch keine vorhandenen array-contains- und vector-Indextypen. Anstatt solche Abfragen einfach abzulehnen, versucht Cloud Firestore, andere vorhandene ascending- und descending-Indexe zu verwenden. Es ist davon auszugehen, dass Ausdrücke mit array_contains oder find_nearest dadurch langsamer sind als ihre bestehenden Äquivalente.
Echtzeit- und Offline-Unterstützung
Pipelinevorgänge bieten keine Echtzeit- und Offlinefunktionen.
Nächste Schritte
- Beginnen Sie mit der Referenzdokumentation zu Funktionen und Phasen.
- Joins mit Unterabfragen ausführen