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, mit denen sich komplexe Transformationen ausführen lassen.
Einstieg
Informationen zum Installieren und Initialisieren von Client-SDKs finden Sie in den folgenden Anleitungen:
Syntax
In den folgenden Abschnitten erhalten Sie einen Überblick über die Syntax für Pipelinevorgänge.
Konzepte
Ein wichtiger Unterschied zu Pipeline-Vorgängen ist die Einführung einer expliziten Reihenfolge für Phasen. So lassen sich komplexere Abfragen formulieren. Dies ist jedoch eine erhebliche Abweichung von der vorhandenen Abfrageschnittstelle mit Core-Vorgängen, bei der die Reihenfolge der Phasen impliziert wurde. Hier ein Beispiel für Pipeline-Vorgä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) )
Initialisierung
Pipelinevorgänge haben eine sehr vertraute Syntax, die von vorhandenen Cloud Firestore-Abfragen stammt. Um zu beginnen, initialisieren Sie eine Abfrage mit dem folgenden Befehl:
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()
Struktur
Beim Erstellen von Pipelinevorgängen sind einige Begriffe wichtig: Phasen, Ausdrücke, Funktionen und Wrapper für Unterabfragen.

Phasen:Eine Pipeline kann aus einer oder mehreren Phasen bestehen. Logisch gesehen stellen sie die Reihe von Schritten (oder Phasen) dar, die zum Ausführen der Abfrage erforderlich sind.
Ausdrücke:In vielen Phasen wird ein Ausdruck akzeptiert, 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 erstellen, 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.
Felder beziehen sich auf Daten in Dokumenten und Konstanten ermöglichen es, einen beliebigen Wert als Argument für einen Ausdruck anzugeben. Mit Variablen können temporäre Werte definiert und verwendet werden, die auf die Ausführung der Abfrage und nicht auf die verarbeiteten Dokumente beschränkt sind. Im Folgenden finden Sie einen Überblick ü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 | Verwenden Sie temporäre Werte während der Pipelineausführung. |
| SDK-Nutzung | field("name") |
constant("val") |
variable("name") |
| Ebene | lokal für das aktuelle Dokument | global | global für Pipeline und untergeordnete Pipelines |
| Nicht definierte Referenz | wird mit absent ausgewertet. |
– | Laufzeitfehler wird generiert |
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"))) )
Phasen
Eingabephasen
Die Eingabephase ist die erste Phase einer Abfrage. Sie definiert die ursprüngliche Gruppe von Dokumenten, die Sie abfragen. Bei Pipeline-Vorgängen ähnelt dies weitgehend den vorhandenen Abfragen, bei denen die meisten Abfragen entweder mit einer collection(...)- oder einer collection_group(...)-Phase beginnen. Zwei neue Eingabephasen sind database() und documents(...). Mit database() können alle Dokumente in der Datenbank zurückgegeben werden, während documents(...) wie ein Batchlesevorgang funktioniert.
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() )
Wie bei allen anderen Phasen ist die Reihenfolge der Ergebnisse aus diesen Eingabephasen nicht stabil. Der Operator sort(...) sollte immer hinzugefügt werden, wenn eine bestimmte Reihenfolge erforderlich ist.
WHERE
Die Phase where(...) dient als Standardfiltervorgang für Dokumente, die in der vorherigen Phase generiert wurden, und entspricht größtenteils der vorhandenen „where“-Syntax für vorhandene Abfragen. Alle Dokumente, für die ein bestimmter Ausdruck einen Wert ungleich true ergibt, werden aus den zurückgegebenen Dokumenten herausgefiltert.
Mehrere where(...)-Anweisungen können verkettet werden und als and(...)-Ausdruck fungieren. Die folgenden beiden Abfragen sind beispielsweise logisch gleichwertig und können austauschbar 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() )
Felder auswählen / hinzufügen und entfernen
Mit select(...), add_fields(...) und remove_fields(...) können Sie die Felder ändern, die in 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. Mit select(...) werden nur die Dokumente mit den angegebenen Feldnamen zurückgegeben, 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. Wenn Sie Feldnamen angeben, die nicht vorhanden sind, passiert nichts.
Weitere Informationen finden Sie unten im Abschnitt Zurückzugebende Felder einschränken. Im Allgemeinen ist es jedoch hilfreich, eine solche Phase zu verwenden, um das Ergebnis auf die Felder zu beschränken, die im Client benötigt werden. So lassen sich die Kosten und die Latenz für die meisten Anfragen 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. Es kann jedoch ein optionales grouping-Argument angegeben werden, mit dem die Eingabedokumente in verschiedenen Buckets zusammengefasst werden können.
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() )
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 Punkten 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() )
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: So sieht die Struktur einer typischen Anfrage aus:

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 sich vertraut machen 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() )
Limits
In der Enterprise-Version gibt es in den meisten Fällen keine Einschränkungen hinsichtlich der Form der Anfrage. 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-Edition).
- Arbeitsspeichernutzung:128 MiB-Grenze für die Menge der materialisierten Daten während der Abfrageausführung.
Fehler
Es kann verschiedene Gründe für fehlgeschlagene Anfragen geben. Hier finden Sie einen Link zu häufigen Fehlern und den zugehörigen Maßnahmen, die Sie ergreifen können:
| Fehlercode | Aktion |
DEADLINE_EXCEEDED
|
Die Ausführung der Abfrage dauert länger als 60 Sekunden und erfordert eine zusätzliche Optimierung. Tipps finden Sie im Abschnitt „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 Arbeitsspeicherlimits und muss zusätzlich optimiert werden. Tipps finden Sie im Abschnitt „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
Bei 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 mit dem Fehler FAILED_PRECONDITION missing index sofort 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 ermitteln, 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 Indexe anhand der vorhandenen Dokumentation zur Indexverwaltung 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 zum Erstellen von Indexen mit Feldern in der folgenden Reihenfolge beachten:
- Alle Felder, die in Gleichheitsfiltern verwendet werden (in beliebiger Reihenfolge)
- Alle Felder, nach denen sortiert werden soll (in derselben Reihenfolge)
- Felder, die in Bereichs- oder Ungleichheitsfiltern verwendet werden, in absteigender Reihenfolge der Selektivität der Abfragebeschränkung
Beispiel:
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() )
Der empfohlene Index ist ein Index mit Sammlungsumfang für (genre [...], published DESC, avg_rating DESC). in books.
Indexdichte
Cloud Firestore unterstützt sowohl spärliche als auch nicht spärliche Indexe. Weitere Informationen finden Sie unter Indexdichte.
Abgedeckte Anfragen + sekundäre Indexe
Mit Cloud Firestore kann das Abrufen des vollständigen Dokuments übersprungen und nur Ergebnisse aus dem Index zurückgegeben werden, wenn alle zurückgegebenen Felder in einem sekundären Index vorhanden sind. Dies führt in der Regel zu einer deutlichen Verbesserung der Latenz und der Kosten. 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() )
Wenn die Datenbank bereits einen Index mit Sammlungsbereich für books für (category [...], title [...], author [...]) hat, muss nichts aus den Hauptdokumenten abgerufen werden. In diesem Fall spielt die Reihenfolge im Index keine Rolle. Das wird durch [...] angegeben.
Zurückzugebende Felder einschränken
Standardmäßig gibt eine Cloud Firestore-Abfrage alle Felder in einem Dokument zurück, analog zu einer SELECT * in relationalen Systemen. Wenn Ihre Anwendung jedoch nur eine Teilmenge 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 (wodurch die Kosten für ausgehenden Netzwerkverkehr sinken) als auch die Latenz verringert.
Tools zur Fehlerbehebung
Query Explain
Mit Query Explain können Sie Ausführungsmesswerte und Details zu verwendeten Indexen einsehen.
Messwerte
Pipelinevorgänge sind vollständig in die vorhandenen Cloud Firestore-Messwerte integriert.
Bekannte Probleme / Einschränkungen
Spezialisierte Indexe
Pipelinevorgänge unterstützen noch keine vorhandenen array-contains- und vector-Indextypen. Anstatt solche Anfragen einfach abzulehnen, versucht Cloud Firestore, andere vorhandene ascending- und descending-Indizes zu verwenden. Es wird erwartet, dass Pipeline-Vorgänge mit solchen array_contains- oder find_nearest-Ausdrücken während der privaten Vorschau aus diesem Grund langsamer sind als ihre vorhandenen Entsprechungen.
Seitenumbruch
Die einfache Paginierung eines Ergebnissatzes wird während der privaten Vorschau nicht unterstützt. Als Behelfslösung können Sie entsprechende where(...)- und sort(...)-Phasen verketten, wie unten dargestellt.
Web
// Existing pagination via `startAt()` const q = query(collection(db, "cities"), orderBy("population"), startAt(1000000)); // Private preview workaround using pipelines const pageSize = 2; const pipeline = db.pipeline() .collection("cities") .select("name", "population", "__name__") .sort(field("population").descending(), field("__name__").ascending()); // Page 1 results let snapshot = await execute(pipeline.limit(pageSize)); // End of page marker const lastDoc = snapshot.results[snapshot.results.length - 1]; // Page 2 results snapshot = await execute( pipeline .where( or( and( field("population").equal(lastDoc.get("population")), field("__name__").greaterThan(lastDoc.ref) ), field("population").lessThan(lastDoc.get("population")) ) ) .limit(pageSize) );
Swift
// Existing pagination via `start(at:)` let query = db.collection("cities").order(by: "population").start(at: [1000000]) // Private preview workaround using pipelines let pipeline = db.pipeline() .collection("cities") .where(Field("population").greaterThanOrEqual(1000000)) .sort([Field("population").descending()])
Kotlin
// Existing pagination via `startAt()` val query = db.collection("cities").orderBy("population").startAt(1000000) // Private preview workaround using pipelines val pipeline = db.pipeline() .collection("cities") .where(field("population").greaterThanOrEqual(1000000)) .sort(field("population").descending())
Java
// Existing pagination via `startAt()` Query query = db.collection("cities").orderBy("population").startAt(1000000); // Private preview workaround using pipelines Pipeline pipeline = db.pipeline() .collection("cities") .where(field("population").greaterThanOrEqual(1000000)) .sort(field("population").descending());
Python
from google.cloud.firestore_v1.pipeline_expressions import Field # Existing pagination via `start_at()` query = ( client.collection("cities") .order_by("population") .start_at({"population": 1_000_000}) ) # Private preview workaround using pipelines pipeline = ( client.pipeline() .collection("cities") .where(Field.of("population").greater_than_or_equal(1_000_000)) .sort(Field.of("population").descending()) )
Emulator-Unterstützung
Der Emulator unterstützt keine Pipelinevorgänge.
Echtzeit- und Offlinesupport
Pipelinevorgänge haben noch keine Echtzeit- und Offlinefunktionen.
Nächste Schritte
- Referenzdokumentation zu Funktionen und Phasen
- Weitere Informationen zum Ausführen von Joins mit Unterabfragen