Hintergrund
Pipeline-Vorgä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 auszuführen.
Erste Schritte
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 Pipeline-Vorgänge.
Konzepte
Ein bemerkenswerter Unterschied bei Pipeline-Vorgängen ist die Einführung einer expliziten Reihenfolge der Phasen. Dadurch können komplexere Abfragen ausgedrückt werden. Dies ist jedoch eine bemerkenswerte Abweichung von der vorhandenen Abfrageschnittstelle mit Core-Vorgängen, bei der die Reihenfolge der Phasen impliziert war. 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
Pipeline-Vorgänge haben eine sehr vertraute Syntax, die von vorhandenen Cloud Firestore Abfragen stammt. 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()
Struktur
Beim Erstellen von Pipeline-Vorgängen sind einige Begriffe wichtig: Phasen, Ausdrücke und Funktionen.

Phasen:Eine Pipeline kann aus einer oder mehreren Phasen bestehen. Logisch stellen diese die Reihe von Schritten (oder Phasen) dar, die zum Ausführen der Abfrage erforderlich sind. Hinweis: In der Praxis werden Phasen möglicherweise in einer anderen Reihenfolge ausgeführt, um die Leistung zu verbessern. Dies ändert jedoch nichts an der Absicht oder Richtigkeit der Abfrage.
Ausdrücke:Phasen akzeptieren oft einen Ausdruck, mit dem Sie komplexere Abfragen ausdrücken können. Ausdrücke können 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.
Feld- und Konstantenverweise
Pipeline-Vorgänge unterstützen komplexe Ausdrücke. Daher ist es möglicherweise erforderlich, zu unterscheiden, ob ein Wert ein Feld oder eine Konstante darstellt. Dazu ein Beispiel:
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 anfängliche Menge von Dokumenten, die Sie abfragen. Bei Pipeline-Vorgängen ähnelt dies weitgehend den vorhandenen Abfragen, bei denen die meisten Abfragen mit einer collection(...)- oder 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 Batch-Lesevorgang 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. Wenn eine bestimmte Reihenfolge gewünscht ist, sollte immer ein sort(...)-Operator hinzugefügt werden.
Dabei gilt:
Die where(...)-Phase fungiert als herkömmlicher Filtervorgang für Dokumente, die in der vorherigen Phase generiert wurden, und entspricht weitgehend der vorhandenen „where“-Syntax für vorhandene Abfragen. Alle Dokumente, für die ein bestimmter Ausdruck nicht true ergibt, werden aus den zurückgegebenen Dokumenten herausgefiltert.
Mehrere where(...)-Anweisungen können miteinander verknüpft werden und fungieren als and(...)-Ausdruck. 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() )
Auswählen / Felder 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 Phasen im Projektionsstil bezeichnet.
Mit select(...) und add_fields(...) können Sie das Ergebnis eines Ausdrucks einem vom Nutzer angegebenen Feldnamen zuweisen. Ein Ausdruck, der zu einem Fehler führt, ergibt einen null-Wert. select(...) gibt nur die Dokumente mit den angegebenen Feldnamen zurück, während add_fields(...) das Schema der vorherigen Phase erweitert (wobei Werte mit identischen Feldnamen möglicherweise überschrieben werden).
Mit remove_fields(...) können Sie eine Reihe von Feldern angeben, die aus der vorherigen Phase entfernt werden sollen. Das Angeben von Feldnamen, die nicht vorhanden sind, hat keine Auswirkungen.
Weitere Informationen finden Sie unten im Abschnitt Felder einschränken, die zurückgegeben werden sollen. 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, um die Kosten und die Latenz für die meisten Abfragen zu reduzieren.
Aggregieren / Eindeutig
Mit der aggregate(...)-Phase können Sie eine Reihe von Aggregationen für die Eingabedokumente ausführen. Standardmäßig werden alle Dokumente zusammen aggregiert. Sie können jedoch optional ein grouping-Argument angeben, mit dem die Eingabedokumente in verschiedenen Buckets aggregiert 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 distinct(...)-Phase ist ein vereinfachter Aggregationsoperator, mit dem nur die eindeutigen groupings ohne Akkumulatoren generiert werden können. In allen anderen Punkten verhält sie sich identisch mit aggregate(...). Hier ein Beispiel:
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: 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() )
Limits
In den meisten Fällen gibt es in der Enterprise Edition 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 Hauptlimits, die Sie beachten sollten:
- Frist:60 Sekunden (identisch mit der Standard Edition).
- Arbeitsspeichernutzung:128 MiB-Limit für die Menge der materialisierten Daten während der Abfrageausführung.
Fehler
Es kann verschiedene Gründe geben, warum Abfragen fehlschlagen. 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 Abfrage, die Sie ausführen, überschreitet eine Frist von 60 Sekunden und muss zusätzlich optimiert werden. Tipps finden Sie im Abschnitt zur Leistung. Wenn Sie die Ursache des Problems nicht finden können, wenden Sie sich an das Team. |
RESOURCE_EXHAUSTED
|
Die Abfrage, die Sie ausführen, überschreitet die Arbeitsspeicherlimits und muss zusätzlich optimiert werden. Tipps finden Sie im Abschnitt zur Leistung. Wenn Sie die Ursache des Problems nicht finden können, wenden Sie sich an das Team. |
INTERNAL
|
Wenden Sie sich an das Team, um Support zu erhalten. |
Leistung
Im Gegensatz zu vorhandenen Abfragen ist bei Pipeline-Vorgängen nicht immer ein Index erforderlich. Das bedeutet, dass eine Abfrage eine höhere Latenz aufweisen kann als vorhandene Abfragen, die sofort mit einem FAILED_PRECONDITION-Fehler aufgrund eines fehlenden 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 verarbeitet wird oder auf einen weniger effizienten Vorgang wie einen Tabellenscan zurückgreift. Wenn Ihre Abfrage nicht vollständig von einem Index verarbeitet wird, können Sie einen Index erstellen. Folgen Sie dazu der Anleitung.
Indexe erstellen
Sie können Indexe gemäß 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, folgen Sie den Best Practices, 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
Für die folgende Abfrage beispielsweise:
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 Sammlungsbereich für books für (genre [...], published DESC, avg_rating DESC).
Indexdichte
Cloud Firestore unterstützt Sparse- und Nicht-Sparse-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. Hier ein Beispiel für eine Abfrage:
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 [...] angezeigt.
Felder einschränken, die zurückgegeben werden sollen
Standardmäßig gibt eine Cloud Firestore Abfrage alle Felder in einem Dokument zurück, ähnlich wie SELECT * in herkömmlichen 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 werden sowohl die Antwortgröße (und damit die Kosten für den ausgehenden Netzwerktraffic) als auch die Latenz reduziert.
Tools zur Fehlerbehebung
Query Explain
Mit Query Explain können Sie Ausführungsmesswerte und Details zu den verwendeten Indexen einsehen.
Messwerte
Pipeline-Vorgänge sind vollständig in die vorhandenen Cloud Firestore Messwerte integriert.
Bekannte Probleme und Einschränkungen
Spezialisierte Indexe
Pipeline-Vorgänge unterstützen noch nicht die vorhandenen array-contains & vector Indexe vom Typ. Anstatt solche Abfragen einfach abzulehnen, versucht Cloud Firestore, andere vorhandene ascending & descending-Indexe zu verwenden. Es wird erwartet, dass Pipeline-Vorgänge mit solchen array_contains- oder find_nearest-Ausdrücken während der privaten Vorschau langsamer sind als ihre vorhandenen Entsprechungen.
Seitenumbruch
Die Unterstützung für das einfache Paginieren eines Ergebnissatzes wird während der privaten Vorschau nicht unterstützt. Sie können dies umgehen, indem Sie entsprechende where(...)- und sort(...)-Phasen verketten, wie unten gezeigt.
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 Pipeline-Vorgänge.
Echtzeit- und Offlineunterstützung
Pipeline-Vorgänge bieten noch keine Echtzeit- und Offlinefunktionen.
Nächste Schritte
- Beginnen Sie mit der Referenzdokumentation zu Funktionen und Phasen.