Latar belakang
Kueri Pipeline adalah antarmuka kueri baru untuk Firestore. Fitur ini menyediakan
fungsi kueri tingkat lanjut, termasuk ekspresi kompleks. Fitur ini juga menambahkan dukungan untuk berbagai
fungsi baru seperti min, max, substring, regex_match dan array_contains_all.
Dengan Kueri Pipeline, pembuatan indeks juga sepenuhnya bersifat opsional, sehingga menyederhanakan
proses pengembangan kueri baru. Kueri Pipeline juga menghilangkan berbagai
batasan pada bentuk kueri, sehingga Anda dapat menentukan kueri in atau or yang besar.
Memulai
Untuk menginstal dan menginisialisasi SDK klien, lihat petunjuk di Panduan memulai.
Sintaksis
Bagian berikut memberikan ringkasan sintaksis untuk Kueri Pipeline.
Konsep
Salah satu perbedaan penting di Kueri Pipeline adalah penerapan pengurutan "tahap" secara eksplisit. Dengan ini, Anda dapat mengekspresikan kueri yang lebih kompleks. Namun, ini merupakan penyimpangan yang signifikan dari antarmuka kueri yang sudah ada, yang urutan tahapnya bersifat implisit. Perhatikan contoh Kueri Pipeline berikut:
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) )
Inisialisasi
Kueri Pipeline memiliki sintaksis yang sangat familier yang berasal dari kueri Cloud Firestore yang ada. Untuk memulai, Anda harus menginisialisasi kueri dengan menulis perintah berikut:
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
Ada beberapa istilah yang penting untuk dipahami saat membuat Kueri Pipeline: tahap, ekspresi, dan fungsi.

Tahap: Pipeline dapat terdiri dari satu atau beberapa tahap. Secara logis, ini mewakili serangkaian langkah (atau tahap) yang dilakukan untuk menjalankan kueri. Catatan: Dalam praktiknya, tahap dapat dijalankan di luar urutan untuk meningkatkan performa. Namun, hal ini tidak mengubah maksud atau kebenaran kueri.
Ekspresi: Tahap sering kali menerima ekspresi yang memungkinkan Anda mengekspresikan kueri yang lebih kompleks. Ekspresi bisa jadi sederhana dan terdiri dari satu fungsi seperti eq("a", 1). Anda juga dapat membuat ekspresi yang lebih kompleks dengan menyusun ekspresi seperti and(eq("a", 1), eq("b", 2)).
Referensi Kolom vs. Konstan
Kueri Pipeline mendukung ekspresi yang kompleks. Oleh karena itu, mungkin perlu dibedakan apakah suatu nilai merepresentasikan kolom atau konstan. Perhatikan contoh berikut:
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"))) )
Tahap
Tahap Input
Tahap input merupakan tahap pertama kueri. Tahap ini menentukan
kumpulan dokumen awal yang Anda kueri. Untuk Kueri Pipeline, tahap ini sangat
mirip dengan kueri yang sudah ada, yang sebagian besar kuerinya dimulai dengan tahap
collection(...) atau collection_group(...). Dua tahap input barunya adalah
database() dan documents(...). Dengan database(), semua dokumen dapat
ditampilkan dalam database. Sementara itu, documents(...) berfungsi mirip dengan operasi baca
secara massal.
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() )
Seperti semua tahap lainnya, urutan hasil dari tahap input ini tidak
stabil. Operator sort(...) harus selalu ditambahkan jika urutan tertentu
diinginkan.
Di mana
Tahap where(...) berfungsi sebagai operasi filter tradisional pada dokumen
yang dihasilkan dari tahap sebelumnya dan sebagian besar mencerminkan sintaksis "where"
yang ada untuk kueri yang sudah ada. Dokumen apa pun yang ekspresinya menghasilkan nilai
yang bukan true akan difilter dari dokumen yang ditampilkan.
Beberapa pernyataan where(...) dapat dirangkai bersama, dan bertindak sebagai ekspresi and(...). Misalnya, dua kueri berikut secara logis setara dan dapat digunakan secara bergantian.
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() )
Select/Add & Remove Fields
select(...), add_fields(...) & remove_fields(...) memungkinkan Anda
mengubah kolom yang ditampilkan dari tahap sebelumnya. Ketiga tahap ini
umumnya disebut sebagai tahap gaya proyeksi.
select(...) dan add_fields(...) memungkinkan Anda menentukan hasil
ekspresi ke nama kolom yang disediakan pengguna. Ekspresi yang menghasilkan error
akan menghasilkan nilai null. select(...) hanya akan menampilkan dokumen
dengan nama kolom yang ditentukan, sedangkan add_fields(...) akan memperluas skema
tahap sebelumnya (kemungkinan akan menimpa nilai dengan nama kolom yang mirip).
remove_fields(...) memungkinkan penentuan sekumpulan kolom yang akan dihapus dari
tahap sebelumnya. Tidak ada operasi yang dilakukan jika nama kolom yang ditentukan tidak ada.
Lihat bagian Membatasi Kolom yang Ditampilkan di bawah. Namun secara umum, penggunaan tahap tersebut untuk membatasi hasil hanya pada kolom yang diperlukan di klien akan membantu mengurangi biaya dan latensi untuk sebagian besar kueri.
Aggregate/Distinct
Tahap aggregate(...) memungkinkan Anda melakukan serangkaian penggabungan pada dokumen input. Secara default, semua dokumen digabungkan, tetapi argumen grouping opsional dapat diberikan, sehingga dokumen input dapat digabungkan ke dalam bucket yang berbeda.
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() )
Jika groupings tidak ditentukan, tahap ini hanya akan menghasilkan satu dokumen, atau dokumen akan dibuat untuk setiap kombinasi unik nilai groupings.
Tahap distinct(...) adalah operator penggabungan yang disederhanakan yang memungkinkan pembuatan groupings unik secara khusus tanpa akumulator. Perilakunya mirip dengan aggregate(...) dalam segala aspek lainnya. Berikut contohnya:
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() )
Fungsi
Fungsi adalah elemen penyusun untuk membuat ekspresi dan kueri yang kompleks. Untuk mengetahui daftar lengkap fungsi beserta contohnya, lihat Referensi fungsi. Sebagai pengingat, pertimbangkan struktur kueri umum:

Banyak tahap menerima ekspresi yang berisi satu atau beberapa fungsi. Penggunaan fungsi yang paling umum akan ditemukan di tahap where(...) dan select(...). Ada dua jenis fungsi utama yang harus Anda ketahui:
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() )
Batas
Pada umumnya, Edisi Enterprise tidak membatasi bentuk
kueri. Dengan kata lain, Anda tidak dibatasi untuk hanya menggunakan sejumlah kecil nilai dalam kueri IN
atau OR. Namun, ada dua batasan utama yang harus Anda ketahui:
- Batas waktu: 60 detik (sama dengan Edisi Standard).
- Penggunaan Memori: Batas 128 MiB untuk jumlah data yang diwujudkan selama eksekusi kueri.
Error
Anda bisa saja mengalami kegagalan kueri karena sejumlah alasan. Berikut link ke error umum dan tindakan terkait yang dapat Anda lakukan:
| Kode Error | Tindakan |
DEADLINE_EXCEEDED
|
Kueri yang Anda jalankan melebihi batas waktu 60 detik dan memerlukan pengoptimalan tambahan. Lihat bagian performa untuk mendapatkan tips. Jika Anda tidak dapat menemukan akar masalahnya, silakan hubungi tim. |
RESOURCE_EXHAUSTED
|
Kueri yang Anda jalankan melebihi batas memori dan memerlukan pengoptimalan tambahan. Lihat bagian performa untuk mendapatkan tips. Jika Anda tidak dapat menemukan akar masalahnya, silakan hubungi tim. |
INTERNAL
|
Hubungi tim untuk mendapatkan dukungan. |
Performa
Tidak seperti kueri yang sudah ada, Kueri Pipeline tidak selalu memerlukan indeks. Artinya, kueri dapat menunjukkan latensi yang lebih tinggi dibandingkan dengan kueri yang sudah ada, yang akan langsung gagal dengan error indeks yang hilang FAILED_PRECONDITION. Untuk meningkatkan performa Kueri Pipeline, ada beberapa langkah yang dapat Anda lakukan.
Membuat Indeks
Indeks yang Digunakan
Dengan Query Explain, Anda dapat mengetahui apakah kueri Anda ditayangkan oleh indeks atau dikembalikan ke operasi yang kurang efisien seperti pemindaian tabel. Jika kueri Anda tidak sepenuhnya ditayangkan dari indeks, Anda dapat membuat indeks dengan mengikuti petunjuk yang ada.
Membuat Indeks
Anda dapat mengikuti dokumentasi pengelolaan indeks yang ada untuk membuat indeks. Sebelum membuat indeks, pahami praktik terbaik umum terkait indeks di Firestore. Untuk memastikan kueri Anda dapat memanfaatkan indeks, ikuti praktik terbaik untuk membuat indeks dengan kolom dalam urutan berikut:
- Semua kolom yang akan digunakan dalam filter kesetaraan (dalam urutan apa pun)
- Semua kolom yang akan diurutkan (dalam urutan yang sama)
- Kolom yang akan digunakan dalam filter rentang atau ketidaksetaraan dalam urutan menurun dari selektivitas batasan kueri
Misalnya, untuk kueri berikut,
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() )
Indeks yang direkomendasikan adalah indeks cakupan koleksi pada books untuk (genre [...], published DESC, avg_rating DESC).
Kepadatan indeks
Cloud Firestore mendukung indeks sparse dan non-sparse. Untuk mengetahui informasi selengkapnya, lihat Kepadatan indeks.
Kueri yang Tercakup + Indeks Sekunder
Firestore dapat melewati pengambilan dokumen lengkap dan hanya menampilkan hasil dari indeks jika semua kolom yang ditampilkan ada dalam indeks sekunder. Hal ini biasanya akan menghasilkan penurunan latensi (dan biaya) yang signifikan. Dengan contoh kueri di bawah:
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() )
Jika database sudah memiliki indeks cakupan koleksi pada books untuk (category [...], title [...], author [...]), database dapat menghindari pengambilan apa pun dari dokumen utama itu sendiri. Dalam kasus ini, urutan dalam indeks tidaklah penting, hal ini ditandai dengan [...].
Membatasi Kolom yang akan Ditampilkan
Secara default, kueri Firestore menampilkan semua kolom dalam dokumen, yang serupa dengan SELECT * dalam sistem tradisional. Namun, jika aplikasi Anda hanya memerlukan sebagian kecil kolom, tahap select(...) atau restrict(...) dapat digunakan untuk mengirim pemfilteran ini ke sisi server. Hal ini akan mengurangi ukuran respons (mengurangi biaya egress jaringan) sekaligus mengurangi latensi.
Alat Pemecahan Masalah
Query Explain
Dengan Query Explain, Anda dapat memiliki visibilitas terkait metrik eksekusi dan detail tentang indeks yang digunakan.
Metrik
Kueri Pipeline terintegrasi sepenuhnya dengan metrik Firestore yang ada.
Masalah Umum/Batasan
Indeks Khusus
Kueri Pipeline belum mendukung jenis indeks array-contains & vector yang ada. Agar tidak terus-menerus menolak kueri tersebut, Firestore akan mencoba menggunakan indeks ascending & descending lainnya yang ada. Selama pratinjau pribadi, kueri Pipeline dengan ekspresi array_contains atau find_nearest tersebut diperkirakan akan lebih lambat daripada kueri yang setara karena hal ini.
Penomoran halaman
Dukungan untuk penomoran halaman yang mudah di set hasil tidak didukung selama pratinjau pribadi. Hal ini dapat diatasi dengan menggabungkan tahap where(...) & sort(...) yang setara seperti yang ditunjukkan di bawah.
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()) )
Dukungan Emulator
Emulator belum mendukung kueri Pipeline.
Dukungan Real-time dan Offline
Kueri pipeline belum memiliki kemampuan real-time dan offline.
Langkah berikutnya
- Mulai pelajari dokumentasi referensi Fungsi dan Tahap.