Firestore Pipeline işlemleriyle veri alma

Arka plan

İşlem hattı işlemleri, Cloud Firestore için yeni bir sorgu arayüzüdür. Bu arayüz, karmaşık ifadeler içeren gelişmiş sorgu işlevleri sunar. Ayrıca min, max, substring, regex_match ve array_contains_all gibi birçok yeni işlev için destek ekler.

Dönüşüm hunisi işlemleriyle dizin oluşturma da tamamen isteğe bağlıdır ve yeni sorgu geliştirme sürecini kolaylaştırır. Ardışık düzen işlemleri, sorgu şekliyle ilgili birçok sınırlamayı da kaldırarak büyük in veya or sorguları belirtmenize olanak tanır.

Başlarken

İstemci SDK'larını yüklemek ve başlatmak için aşağıdaki kılavuzlardaki talimatlara bakın:

Söz dizimi

Aşağıdaki bölümlerde, Pipeline işlemlerinin söz dizimine genel bir bakış sunulmaktadır.

Kavramlar

İşlem hattı işlemlerindeki önemli bir fark, açık "aşama" sıralamasının kullanıma sunulmasıdır. Bu sayede daha karmaşık sorgular ifade edilebilir. Ancak bu, aşamaların sıralamasının ima edildiği mevcut sorgu arayüzünden (Temel işlemler) önemli bir sapmadır. Aşağıdaki Pipeline işlemi örneğini inceleyin:

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)
)

Başlatma

Pipeline işlemlerinin, mevcut Cloud Firestore sorgularından gelen çok tanıdık bir söz dizimi vardır. Başlamak için aşağıdaki kodu yazarak bir sorgu başlatırsınız:

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()

Yapı

Aşamalar, ifadeler ve işlevler olmak üzere, boru hattı işlemleri oluştururken anlamanız gereken birkaç terim vardır.

Bir sorgudaki aşamaları ve ifadeleri gösteren örnek

Aşamalar: Bir işlem hattı bir veya daha fazla aşamadan oluşabilir. Bunlar, sorguyu yürütmek için gerçekleştirilen adımlar (veya aşamalar) dizisini mantıksal olarak temsil eder. Not: Uygulamada, performansı artırmak için aşamalar sırayla yürütülmeyebilir. Ancak bu, sorgunun amacını veya doğruluğunu değiştirmez.

İfadeler: Aşamalar genellikle daha karmaşık sorguları ifade etmenize olanak tanıyan bir ifadeyi kabul eder. İfade basit olabilir ve eq("a", 1) gibi tek bir işlevden oluşabilir. Ayrıca and(eq("a", 1), eq("b", 2)). gibi ifadeleri iç içe yerleştirerek daha karmaşık ifadeler de belirtebilirsiniz.

Alan ve Sabit Referanslar

Ardışık düzen işlemleri, karmaşık ifadeleri destekler. Bu nedenle, bir değerin alanı mı yoksa sabiti mi temsil ettiğini ayırt etmek gerekebilir. Aşağıdaki örneği inceleyin:

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")))
)

Sahneler

Giriş Aşamaları

Giriş aşaması, bir sorgunun ilk aşamasını temsil eder. Sorguladığınız ilk belge grubunu tanımlar. İşlem hattı işlemlerinde bu durum, büyük ölçüde mevcut sorgulara benzer. Çoğu sorgu collection(...) veya collection_group(...) aşamasıyla başlar. database() ve documents(...) olmak üzere iki yeni giriş aşaması vardır. database(), veritabanındaki tüm belgelerin döndürülmesine olanak tanırken documents(...), toplu okuma ile aynı şekilde çalışır.

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()
)

Diğer tüm aşamalarda olduğu gibi, bu giriş aşamalarındaki sonuçların sırası da sabit değildir. Belirli bir sıralama isteniyorsa her zaman bir sort(...) operatörü eklenmelidir.

Nerede

where(...) aşaması, önceki aşamadan oluşturulan belgeler üzerinde geleneksel bir filtre işlemi gibi davranır ve mevcut sorgular için mevcut "where" söz dizimini büyük ölçüde yansıtır. Belirli bir ifadenin true dışındaki bir değerle sonuçlandığı tüm dokümanlar, döndürülen dokümanlardan filtrelenir.

Birden fazla where(...) ifadesi birbirine bağlanabilir ve and(...) ifadesi olarak kullanılabilir. Örneğin, aşağıdaki iki sorgu mantıksal olarak eşdeğerdir ve birbirinin yerine kullanılabilir.

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()
)

Alanları Seçme / Ekleme ve Kaldırma

select(...), add_fields(...) ve remove_fields(...), önceki aşamadan döndürülen alanları değiştirmenize olanak tanır. Bu üç aşamaya genellikle projeksiyon tarzı aşamalar denir.

select(...) ve add_fields(...), bir ifadenin sonucunu kullanıcı tarafından sağlanan bir alan adına belirtmenize olanak tanır. Hatayla sonuçlanan bir ifade null değeriyle sonuçlanır. select(...) yalnızca belirtilen alan adlarına sahip belgeleri döndürürken add_fields(...) önceki aşamanın şemasını genişletir (değerleri aynı alan adlarıyla potansiyel olarak üzerine yazar).

remove_fields(...), önceki aşamadan kaldırılacak bir alan kümesinin belirtilmesine olanak tanır. Mevcut olmayan alan adlarının belirtilmesi işlem yapılmamasına neden olur.

Aşağıdaki Döndürülecek Alanları Kısıtlama bölümüne bakın. Ancak genel olarak, sonucu yalnızca istemcide gereken alanlarla kısıtlamak için böyle bir aşama kullanmak çoğu sorgunun maliyetini ve gecikmesini azaltmaya yardımcı olur.

Toplama / Farklı

aggregate(...) aşaması, giriş dokümanları üzerinde bir dizi toplama işlemi yapmanıza olanak tanır. Varsayılan olarak tüm belgeler birlikte toplanır ancak isteğe bağlı bir grouping bağımsız değişken sağlanabilir. Bu, giriş belgelerinin farklı gruplar halinde toplanmasına olanak tanır.

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()
)

groupings belirtilmediğinde bu aşamada yalnızca tek bir belge oluşturulur. Aksi takdirde, groupings değerlerinin her benzersiz kombinasyonu için bir belge oluşturulur.

distinct(...) aşaması, yalnızca benzersiz groupings değerlerinin oluşturulmasına olanak tanıyan, basitleştirilmiş bir toplama operatörüdür. Diğer tüm açılardan aggregate(...) ile aynı şekilde çalışır. Aşağıda bir örnek verilmiştir:

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()
)

İşlevler

İşlevler, ifadeler ve karmaşık sorgular oluşturmak için kullanılan bir yapı taşıdır. Örneklerle birlikte işlevlerin tam listesi için İşlevler referansı başlıklı makaleye bakın. Kısa bir hatırlatma olarak, tipik bir sorgunun yapısını göz önünde bulundurun:

Bir sorgudaki aşamaları ve işlevleri gösteren örnek

Birçok aşama, bir veya daha fazla işlev içeren ifadeleri kabul eder. En yaygın işlev kullanımı where(...) ve select(...) aşamalarında bulunur. Bilmeniz gereken iki ana işlev türü vardır:

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()
)

Sınırlar

Enterprise sürümü, sorgunun şekliyle ilgili çoğunlukla sınırlama getirmez. Başka bir deyişle, IN veya OR sorgusunda az sayıda değerle sınırlı kalmazsınız. Bunun yerine, bilmeniz gereken iki temel sınır vardır:

  • Son tarih: 60 saniye (Standard Edition ile aynıdır).
  • Bellek Kullanımı: Sorgu yürütme sırasında somutlaştırılan veri miktarı için 128 MiB sınırı.

Hatalar

Sorguların başarısız olmasının çeşitli nedenleri olabilir. Sık karşılaşılan hatalar ve bunlarla ilgili olarak yapabileceğiniz işlemlerin bağlantısını aşağıda bulabilirsiniz:

Hata Kodu İşlem
DEADLINE_EXCEEDED Çalıştırdığınız sorgu 60 saniyelik son tarihi aşıyor ve ek optimizasyon gerektiriyor. İpuçları için performans bölümüne bakın. Sorunun temel nedenini belirleyemiyorsanız ekiple iletişime geçin.
RESOURCE_EXHAUSTED Yürüttüğünüz sorgu, bellek sınırlarını aşıyor ve ek optimizasyon gerektiriyor. İpuçları için performans bölümüne bakın. Sorunun temel nedenini belirleyemiyorsanız ekiple iletişime geçin.
INTERNAL Destek için ekiple iletişime geçin.

Performans

Mevcut sorgulardan farklı olarak, ardışık düzen işlemlerinde her zaman bir dizin bulunması gerekmez. Bu, bir sorgunun, yalnızca FAILED_PRECONDITION eksik dizin hatasıyla hemen başarısız olacak mevcut sorgulara kıyasla daha yüksek gecikme süresi gösterebileceği anlamına gelir. Pipeline işlemlerinin performansını artırmak için uygulayabileceğiniz birkaç adım vardır.

Dizin Oluşturma

Kullanılan Dizin

Sorgu açıklama, sorgunuzun bir dizin tarafından yayınlanıp yayınlanmadığını veya tablo taraması gibi daha az verimli bir işleme geri dönüp dönmediğini belirlemenize olanak tanır. Sorgunuz bir dizinden tam olarak karşılanmıyorsa talimatları uygulayarak bir dizin oluşturabilirsiniz.

Dizin oluşturma

Dizin oluşturmak için mevcut dizin yönetimi belgelerini inceleyebilirsiniz. Dizin oluşturmadan önce Cloud Firestore'deki dizinlerle ilgili genel en iyi uygulamalar hakkında bilgi edinin. Sorgunuzun dizinlerden yararlanabilmesi için aşağıdaki sırayla alanlar içeren dizinler oluşturmaya yönelik en iyi uygulamaları izleyin:

  1. Eşitlik filtrelerinde kullanılacak tüm alanlar (herhangi bir sırada)
  2. Sıralanacak tüm alanlar (aynı sırada)
  3. Sorgu kısıtlaması seçiciliği azalan düzende, aralık veya eşitsizlik filtrelerinde kullanılacak alanlar

Örneğin, aşağıdaki sorgu için

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()
)

Önerilen dizin, (genre [...], published DESC, avg_rating DESC). için books üzerinde bir koleksiyon kapsamı dizinidir.

Dizin yoğunluğu

Cloud Firestore, seyrek ve seyrek olmayan dizinleri destekler. Daha fazla bilgi için Dizin yoğunluğu konusuna bakın.

Kapsanan Sorgular + İkincil Dizinler

Cloud Firestore, döndürülen tüm alanlar ikincil bir dizinde mevcutsa tam belgeyi getirme işlemini atlayabilir ve yalnızca dizindeki sonuçları döndürebilir. Bu durum genellikle önemli bir gecikme (ve maliyet) iyileşmesine yol açar. Aşağıdaki örnek sorguyu kullanarak:

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()
)

Veritabanında books için (category [...], title [...], author [...]) üzerinde zaten bir koleksiyon kapsamı dizini varsa ana dokümanlardan herhangi bir şey getirmekten kaçınabilir. Bu durumda, dizindeki sıra önemli değildir. Bunu belirtmek için [...] kullanılır.

Döndürülecek Alanları Sınırlandırma

Varsayılan olarak, Cloud Firestore sorgusu, geleneksel sistemlerdeki SELECT * sorgusuna benzer şekilde bir dokümandaki tüm alanları döndürür. Ancak uygulamanızın yalnızca alanların bir alt kümesine ihtiyacı varsa bu filtrelemeyi sunucu tarafında zorlamak için select(...) veya restrict(...) aşamaları kullanılabilir. Bu, hem yanıt boyutunu (ağ çıkışı maliyetini düşürerek) azaltır hem de gecikmeyi iyileştirir.

Sorun Giderme Araçları

Sorguyu Açıklama

Query Explain, yürütme metrikleri ve kullanılan dizinlerle ilgili ayrıntılar hakkında görünürlük elde etmenizi sağlar.

Metrikler

Tamamen mevcut Cloud Firestore metrikleriyle entegre edilmişse işlem hattı işlemleri.

Bilinen Sorunlar / Sınırlamalar

Özel Dizinler

Ardışık düzen işlemleri henüz mevcut array-contains ve vector dizin türlerini desteklemiyor. Cloud Firestore, bu tür sorguları yalnızca reddetmek yerine mevcut diğer ascending ve descending dizinlerini kullanmaya çalışır. Bu nedenle, özel önizleme sırasında bu tür array_contains veya find_nearest ifadeleri içeren işlem hattı işlemlerinin mevcut eşdeğerlerinden daha yavaş olması beklenir.

Sayfaları numaralandırma

Sonuç kümesinde kolayca sayfalandırma desteği, özel önizleme sırasında desteklenmez. Bu durum, aşağıda gösterildiği gibi eşdeğer where(...) ve sort(...) aşamaları zincirlenerek çözülebilir.

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())
)

Emülatör Desteği

Emülatör henüz Pipeline işlemlerini desteklemiyor.

Gerçek Zamanlı ve Çevrimdışı Destek

İşlem hattı işlemleri henüz gerçek zamanlı ve çevrimdışı özelliklere sahip değildir.

Sırada ne var?