Firestore Pipeline işlemleriyle veri alma

Arka plan

Ardışık düzen işlemleri, Cloud Firestore için gelişmiş sorgu işlevlerini ve karmaşık ifadeleri destekleyen yeni bir sorgu arayüzü sağlar. min(...), max(...), substring(...), regex_match(...) ve array_contains_all(...) gibi birçok yeni işlev ve karmaşık dönüşümler gerçekleştirebilmek için aşamalar sunar.

Başlarken

İstemci SDK'larını yüklemek ve ilk kullanıma hazırlamak için aşağıdaki kılavuzlardaki talimatlara bakın:

Söz dizimi

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

Kavramlar

Pipeline işlemlerindeki önemli bir fark, açık "aşama" sıralamasının kullanılmasıdır. Bu sayede daha karmaşık sorgular ifade edilebilir. Ancak bu, aşama sıralamasının ima edildiği temel işlemleri kullanan mevcut sorgu arayüzünden önemli bir sapmadır. Aşağıdaki Pipeline işlemleri ö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)
)
Go
pipeline := client.Pipeline().
	Collection("cities").
	Where(firestore.FieldOf("population").GreaterThan(100000)).
	Sort(firestore.Orders(firestore.Ascending(firestore.FieldOf("name")))).
	Limit(10)

Başlatma

Ardışık düzen işlemleri, mevcut Cloud Firestore sorgularından gelen çok tanıdık bir söz dizimine sahiptir. Başlamak için aşağıdaki kodu yazarak bir sorgu başlatın:

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()
Go
client, err := firestore.NewClientWithDatabase(ctx, projectID, databaseID)
if err != nil {
	fmt.Fprintf(w, "firestore.NewClientWithDatabase failed: %v", err)
	return err
}
defer client.Close()
pipeline := client.Pipeline().Collection("books")

Yapı

Ardışık düzen işlemleri oluştururken anlaşılması gereken birkaç terim vardır: aşamalar, ifadeler, işlevler ve alt sorgu sarmalayıcıları.

Sorgudaki aşamaları ve ifadeleri gösteren örnek

Aşamalar: Bir ardışık düzen bir veya daha fazla aşamadan oluşabilir. Mantıksal olarak bunlar, sorguyu yürütmek için gerçekleştirilen bir dizi adımı (veya aşamayı) temsil eder.

İ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. and(eq("a", 1), eq("b", 2)). gibi ifadeleri iç içe yerleştirerek daha karmaşık ifadeler de oluşturabilirsiniz.

Alt sorgu sarmalayıcıları: array() ve scalar() gibi işlevler, iç içe yerleştirilmiş bir ardışık düzeni bir aşamada ifade olarak yerleştirmenize olanak tanır.

Alanlar / Sabitler / Değişkenler

Ardışık düzen işlemleri karmaşık ifadeleri destekler. Bu nedenle, bir değerin alan, sabit veya değişken olup olmadığını ayırt etmek önemlidir.

Alanlar, dokümanlardaki verilere atıfta bulunurken ve sabitler, bir ifadeye bağımsız değişken olarak herhangi bir değerin belirtilmesine olanak tanırken değişkenler, işlenen dokümanlar yerine sorgu yürütme kapsamındaki geçici değerlerin tanımlanmasına ve kullanılmasına olanak tanır. Aşağıda bu kavramlara genel bir bakış sunulmaktadır. Sorgu yürütme sırasında değişkenlerin nasıl okunacağı ve yazılacağı hakkında daha fazla bilgi için let(...) aşamasına bakın.

Alanlar Sabitler Değişkenler
Purpose dokümanlardaki alanlara erişme veya alanları depolama sabit bir değer belirtme Ardışık düzen yürütme sırasında geçici değerler kullanma
SDK Kullanımı field("name") constant("val") variable("name")
Kapsam mevcut dokümana özel dünya geneli ardışık düzen ve alt ardışık düzenler için genel
Tanımlanmamış Referans absent olarak değerlendirilir Yok çalışma zamanı hatası oluşturur

Örnekler:

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")))
)
Go
pipeline := client.Pipeline().Collection("cities").
	Where(firestore.FieldOf("name").Equal(firestore.ConstantOf("Toronto")))

Sahneler

Giriş aşamaları

Giriş aşaması, sorgunun ilk aşamasını temsil eder. Sorguladığınız ilk belge grubunu tanımlar. Pipeline işlemleri için bu, mevcut sorgulara büyük ölçüde benzerdir. Çoğu sorgu collection(...) veya collection_group(...) aşamasıyla başlar. İki yeni giriş aşaması database() ve documents(...)'dir. database(), veritabanındaki tüm belgelerin döndürülmesine olanak tanır. documents(...) ise 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()
)
Go
// Return all restaurants in San Francisco
results1, err := client.Pipeline().Collection("cities/sf/restaurants").Execute(ctx).Results().GetAll()
if err != nil {
	fmt.Fprintf(w, "GetAll failed: %v", err)
	return err
}

// Return all restaurants
results2, err := client.Pipeline().CollectionGroup("restaurants").Execute(ctx).Results().GetAll()
if err != nil {
	fmt.Fprintf(w, "GetAll failed: %v", err)
	return err
}

// Return all documents across all collections in the database (the entire database)
results3, err := client.Pipeline().Database().Execute(ctx).Results().GetAll()
if err != nil {
	fmt.Fprintf(w, "GetAll failed: %v", err)
	return err
}

// Batch read of 3 documents
results4, err := client.Pipeline().
	Documents([]*firestore.DocumentRef{
		client.Collection("cities").Doc("SF"),
		client.Collection("cities").Doc("DC"),
		client.Collection("cities").Doc("NY"),
	}).
	Execute(ctx).Results().GetAll()
if err != nil {
	fmt.Fprintf(w, "GetAll failed: %v", err)
	return err
}

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

Nerede

where(...) aşaması, önceki aşamada oluşturulan belgeler üzerinde standart bir filtre işlemi olarak işlev görür ve çoğunlukla mevcut sorgular için mevcut "where" söz dizimini yansıtır. Belirli bir ifadenin true dışında bir değer olarak değerlendirildiği tüm dokümanlar, döndürülen dokümanlardan filtrelenir.

Birden fazla where(...) ifadesi birbirine bağlanabilir ve and(...) ifadesi olarak işlev görebilir. Ö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()
)
Go
results1, err := client.Pipeline().
	Collection("books").
	Where(firestore.FieldOf("rating").Equal(5)).
	Where(firestore.FieldOf("published").LessThan(1900)).
	Execute(ctx).Results().GetAll()
if err != nil {
	fmt.Fprintf(w, "GetAll failed: %v", err)
	return err
}

results2, err := client.Pipeline().
	Collection("books").
	Where(firestore.And(
		firestore.FieldOf("rating").Equal(5),
		firestore.FieldOf("published").LessThan(1900),
	)).
	Execute(ctx).Results().GetAll()
if err != nil {
	fmt.Fprintf(w, "GetAll failed: %v", err)
	return err
}

Alanları Seçme / Ekleme ve Kaldırma

select(...), add_fields(...) ve remove_fields(...), önceki bir aşamadan döndürülen alanları değiştirmenize olanak tanır. Bu üçü genellikle projeksiyon tarzı sahneler olarak adlandırılır.

select(...) ve add_fields(...), bir ifadenin sonucunu kullanıcı tarafından sağlanan bir alan adına belirtmenize olanak tanır. select(...) yalnızca belirtilen alan adlarına sahip dokümanları döndürürken add_fields(...), önceki aşamanın şemasını genişletir (aynı alan adlarına sahip değerlerin üzerine yazabilir).

remove_fields(...), önceki aşamadan kaldırılacak bir alan grubu belirtmenize 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.

Toplu / Farklı

aggregate(...) aşaması, giriş dokümanları üzerinde bir dizi toplama işlemi yapmanıza olanak tanır. Varsayılan olarak tüm dokümanlar birleştirilir ancak isteğe bağlı bir grouping bağımsız değişkeni sağlanarak giriş dokümanlarının farklı gruplarda birleştirilmesi sağlanabilir.

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()
)
Go
snapshot := client.Pipeline().
	Collection("books").
	Aggregate(
		firestore.Accumulators(firestore.Average("rating").As("avg_rating")),
		firestore.WithAggregateGroups("genre"),
	).
	Execute(ctx)

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

distinct(...) aşaması, herhangi bir toplayıcı olmadan yalnızca benzersiz groupings oluşturmaya olanak tanıyan basitleştirilmiş bir toplama operatörüdür. Diğer tüm açılardan aggregate(...) ile aynı şekilde davranır. Aşağıdaki örnekte şunlar gösterilmektedir:

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()
)
Go
snapshot := client.Pipeline().
	Collection("books").
	Distinct(firestore.Fields(
		firestore.ToUpper(firestore.FieldOf("author")).As("author"),
		firestore.FieldOf("genre"),
	)).
	Execute(ctx)

İş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ı'na bakın. Tipik bir sorgunun yapısını kısaca hatırlayalım:

Sorgudaki aşamaları ve işlevleri gösteren örnek

Birçok aşamada, bir veya daha fazla işlev içeren ifadeler kabul edilir. En yaygın işlev kullanımı, where(...) ve select(...) aşamalarında görülür. 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()
)
Go
// Type 1: Scalar (for use in non-aggregation stages)
// Example: Return the min store price for each book.
results1, err := client.Pipeline().
	Collection("books").
	Select(firestore.Fields(
		firestore.LogicalMinimum(firestore.FieldOf("current"), firestore.FieldOf("updated")).As("price_min"),
	)).
	Execute(ctx).Results().GetAll()
if err != nil {
	fmt.Fprintf(w, "GetAll failed: %v", err)
	return err
}

// Type 2: Aggregation (for use in aggregate stages)
// Example: Return the min price of all books.
results2, err := client.Pipeline().
	Collection("books").
	Aggregate(firestore.Accumulators(
		firestore.Minimum("price").As("min_price"),
	)).
	Execute(ctx).Results().GetAll()
if err != nil {
	fmt.Fprintf(w, "GetAll failed: %v", err)
	return err
}

Sınırlar

Enterprise sürümü, sorgunun şekli konusunda genellikle herhangi bir sınırlama getirmez. Başka bir deyişle, IN veya OR sorgusunda az sayıda değerle sınırlı değilsiniz. Bunun yerine, dikkat etmeniz gereken iki temel sınır vardır:

  • Son tarih: 60 saniye (Standard sürümle aynı).
  • 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 birkaç nedeni olabilir. Sık karşılaşılan hatalar ve bu hatalarla ilgili yapabileceğiniz işlemlerin bağlantısını aşağıda bulabilirsiniz:

Hata Kodu İşlem
DEADLINE_EXCEEDED Yürüttüğünüz sorgu 60 saniyelik süreyi aşıyor ve ek optimizasyon gerektiriyor. İpuçları için performans bölümüne bakın. Sorunun temel nedenini bulamıyorsanı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 bulamıyorsanız ekiple iletişime geçin.
INTERNAL Destek için ekiple iletişime geçin.

Performans

Enterprise sürümü veritabanlarında her zaman bir dizin bulunması gerekmez. Bu, bir sorgunun, FAILED_PRECONDITION eksik dizin hatasıyla hemen başarısız olan mevcut sorgulara kıyasla daha yüksek gecikme 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çıklaması, sorgunuzun bir dizin tarafından mı sunulduğunu yoksa tablo taraması gibi daha az verimli bir işleme mi geri döndüğünü belirlemenize olanak tanır. Sorgunuz bir dizinden tam olarak sunulmuyorsa talimatları uygulayarak dizin oluşturabilirsiniz.

Dizin oluşturma

Dizin oluşturmak için mevcut dizin yönetimi belgelerini inceleyebilirsiniz. Dizin oluşturmadan önce Cloud Firestore uygulamasındaki dizinlerle ilgili genel en iyi uygulamaları öğrenin. Sorgunuzun dizinlerden yararlanabilmesi için aşağıdaki sırayla alanlar içeren dizinler oluşturmak üzere 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ğinin azalan sırasına göre 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()
)
Go
snapshot := client.Pipeline().
	Collection("books").
	Where(firestore.FieldOf("published").LessThan(1900)).
	Where(firestore.FieldOf("genre").Equal("Science Fiction")).
	Where(firestore.FieldOf("rating").GreaterThan(4.3)).
	Sort(firestore.Orders(firestore.Descending(firestore.FieldOf("published")))).
	Execute(ctx)

Ö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 ve İkincil Dizinler

Döndürülen tüm alanlar ikincil bir dizinde mevcutsa Cloud Firestore, dokümanın tamamını getirmeyi atlayabilir ve yalnızca dizinden sonuçları döndürebilir. Bu genellikle gecikme süresinde (ve maliyette) önemli bir iyileşme sağlar. 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()
)
Go
snapshot := client.Pipeline().
	Collection("books").
	Where(firestore.FieldOf("category").Like("%fantasy%")).
	Where(firestore.FieldOf("title").FieldExists()).
	Where(firestore.FieldOf("author").FieldExists()).
	Select(firestore.Fields("title", "author")).
	Execute(ctx)

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

Döndürülecek alanları kısıtlama

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

Sorun Giderme Araçları

Sorgu Açıklaması

Query Explain, yürütme metriklerini ve kullanılan dizinlerle ilgili ayrıntıları görünür hale getirmenize olanak tanır.

Metrikler

Mevcut Cloud Firestore metrikleriyle tam olarak entegre edilmiş ardışık düzen 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ı reddetmek yerine mevcut diğer ascending ve descending dizinlerini kullanmaya çalışır. Bu nedenle, array_contains veya find_nearest ifadelerinin mevcut eşdeğerlerinden daha yavaş olması beklenir.

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

Ardışık düzen işlemlerinde gerçek zamanlı ve çevrimdışı özellikler yoktur.

Sırada ne var?