Hintergrund
Pipelinevorgänge sind eine neue Abfrageschnittstelle für Cloud Firestore.
Diese Oberfläche bietet erweiterte Abfragefunktionen, die komplexe Ausdrücke umfassen. Außerdem werden viele neue Funktionen wie min, max, substring, regex_match und array_contains_all unterstützt.
Mit Pipeline-Vorgängen ist die Indexerstellung auch völlig optional, was die Entwicklung neuer Abfragen vereinfacht. Bei Pipelinevorgängen werden auch viele Einschränkungen für die Abfrageform entfernt, sodass Sie große in- oder or-Abfragen angeben können.
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 Pipeline-Vorgä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 bemerkenswerte Abweichung von der vorhandenen Abfrageschnittstelle (Core-Vorgänge), bei der die Reihenfolge der Phasen impliziert wurde. Hier ein Beispiel für einen Pipelinevorgang:
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 eine Abfrage zu initialisieren, schreiben Sie Folgendes:
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 gesehen stellen sie die Reihe von Schritten (oder Phasen) dar, die zum Ausführen der Abfrage erforderlich sind. Hinweis: In der Praxis können Phasen zur Leistungssteigerung in beliebiger Reihenfolge ausgeführt werden. Dadurch werden jedoch weder die Intention noch die Richtigkeit der Abfrage geändert.
Ausdrücke:In Stages wird häufig 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.
Feld- und konstante Referenzen
Pipelinevorgänge unterstützen komplexe Ausdrücke. Daher kann es erforderlich sein, 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 ursprüngliche Gruppe von Dokumenten, die Sie abfragen. Bei Pipelinevorgängen ähnelt dies weitgehend den vorhandenen Abfragen, bei denen die meisten Abfragen entweder mit einer collection(...)- oder einer collection_group(...)-Phase beginnen. Es gibt zwei neue Eingabephasen: 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. Ein sort(...)-Operator sollte immer hinzugefügt werden, wenn eine bestimmte Reihenfolge gewünscht ist.
WHERE
Die Phase where(...) fungiert als herkömmlicher Filtervorgang für Dokumente, die in der vorherigen Phase generiert wurden. Sie entspricht weitgehend der vorhandenen „where“-Syntax für bestehende Abfragen. Alle Dokumente, für die ein bestimmter Ausdruck zu einem Wert ungleich true ausgewertet wird, 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 Projektionsbühnen 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 den Wert null. Mit select(...) werden nur die Dokumente mit den angegebenen Feldnamen zurückgegeben, während mit add_fields(...) das Schema der vorherigen Phase erweitert wird (dabei werden Werte mit identischen Feldnamen möglicherweise überschrieben).
Mit remove_fields(...) können Sie eine Reihe von Feldern angeben, die aus der vorherigen Phase entfernt werden sollen. Die Angabe von Feldnamen, die nicht vorhanden sind, hat keine Auswirkungen.
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.
Zusammenfassen / 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 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(...). Ein Beispiel sehen Sie unten:
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 Edition gibt es in den meisten Fällen keine Einschränkungen hinsichtlich der Form der Abfrage. Das heißt, Sie sind bei einer IN- oder OR-Abfrage nicht auf eine kleine Anzahl von Werten beschränkt. Stattdessen gibt es zwei primäre Einschränkungen, die Sie beachten sollten:
- Frist:60 Sekunden (identisch mit 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 eine Liste mit 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
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 für 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 ermitteln, ob Ihre Abfrage von einem Index bedient wird oder auf einen weniger effizienten Vorgang wie einen Tabellenscan zurückgreift. Wenn Ihre Anfrage nicht vollständig über einen Index beantwortet wird, können Sie einen Index erstellen.
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
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. Das 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 einem SELECT * in herkömmlichen Systemen. Wenn Ihre Anwendung jedoch nur eine Teilmenge der Felder benötigt, können Sie diese Filterung serverseitig in den Phasen select(...) oder restrict(...) vornehmen. Dadurch wird sowohl die Antwortgröße (und damit die Kosten für ausgehenden Traffic) 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 Pipelinevorgänge noch nicht.
Echtzeit- und Offlinesupport
Pipelinevorgänge haben noch keine Echtzeit- und Offlinefunktionen.