دریافت داده با عملیات Firestore Pipeline

پس‌زمینه

عملیات خط لوله میانای پُرسمان جدیدی برای Cloud Firestore ارائه می‌دهد که از عملکرد پُرسمان پیشرفته و عبارت‌های پیچیده پشتیبانی می‌کند. این زبان توابع جدید بسیاری را معرفی می‌کند، ازجمله min(...)،‏ max(...)، substring(...)،‏ regex_match(...)، و array_contains_all(...)، و مراحلی برای انجام تبدیل‌های پیچیده.

شروع به کار

برای نصب و مقداردهی اولیه کیت‌های توسعه نرم‌افزار کارخواه، به دستورالعمل‌های راهنماهای زیر مراجعه کنید:

نحو

بخش‌های زیر نمای کلی از نحو عملیات Pipeline ارائه می‌دهند.

مفاهیم

یک تفاوت قابل‌توجه با عملیات Pipeline، معرفی ترتیب صریح «مرحله» است. این کار امکان بیان پُرسمان‌های پیچیده‌تر را فراهم می‌کند. بااین‌حال، این انحراف قابل‌توجهی از میانای پُرسمان موجود بااستفاده از عملیات‌های Core است که در آن ترتیب مراحل ضمنی بود. نمونه عملیات Pipeline زیر را درنظر بگیرید:

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);
پایتون
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)
)
رفتن
pipeline := client.Pipeline().
	Collection("cities").
	Where(firestore.FieldOf("population").GreaterThan(100000)).
	Sort(firestore.Orders(firestore.Ascending(firestore.FieldOf("name")))).
	Limit(10)

راه‌اندازی

عملیات خط لوله نحو بسیار آشنایی دارد که از پُرسمان‌های Cloud Firestore موجود می‌آید. برای شروع، با نوشتن عبارت زیر، پُرسمانی را مقداردهی اولیه می‌کنید:

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();
پایتون
firestore_client = firestore.client(default_app, "your-new-enterprise-database")
pipeline = firestore_client.pipeline()
رفتن
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")

ساختار

هنگام ایجاد عملیات Pipeline، درک چند اصطلاح مهم است: مراحل، عبارت‌ها، و توابع و پوشاننده‌های زیرپرس‌وجو.

نمونه‌ای که مراحل و عبارت‌ها را در پُرسمان نشان می‌دهد

مراحل: خط لوله ممکن است از یک یا چند مرحله تشکیل شده باشد. از نظر منطقی، این‌ها نشان‌دهنده مجموعه مراحلی (یا مراحلی) هستند که برای اجرای پُرسمان انجام شده‌اند.

عبارت‌ها: مراحل اغلب عبارتی را می‌پذیرند که به شما امکان می‌دهد پُرسمان‌های پیچیده‌تری را بیان کنید. عبارت ممکن است ساده باشد و از یک تابع تشکیل شده باشد مثل eq("a", 1). همچنین می‌توانید با تودرتو کردن عبارت‌هایی مثل and(eq("a", 1), eq("b", 2)).، عبارت‌های پیچیده‌تری را بیان کنید

پوشاننده‌های زیرپرس‌وجو: توابعی مانند array() و scalar() به شما امکان می‌دهند یک خط لوله تودرتو را به‌عنوان یک عبارت در یک مرحله جاسازی کنید.

فیلدها / ثابت‌ها / متغیرها

عملیات خط لوله از عبارت‌های پیچیده پشتیبانی می‌کند. به همین دلیل، مهم است که تشخیص دهید آیا مقدار نشان‌دهنده فیلد، ثابت، یا متغیر است.

درحالی‌که فیلدها به داده‌های درون اسناد اشاره می‌کنند و ثابت‌ها امکان مشخص کردن هر مقداری را به‌عنوان آرگومان برای عبارت فراهم می‌کنند، متغیرها امکان تعریف و استفاده از مقادیر موقتی را فراهم می‌کنند که به‌جای اسناد درحال پردازش، به اجرای پُرسمان محدود می‌شوند. در ادامه، نمای کلی این مفاهیم ارائه شده است، برای اطلاعات بیشتر درباره نحوه خواندن و نوشتن متغیرها درطول اجرای پُرسمان، به مرحله let(...) مراجعه کنید.

فیلدها ثابت‌ها متغیر
هدف دسترسی به فیلدها یا ذخیره کردن آن‌ها در اسناد مقدار ثابتی را مشخص کنید استفاده از مقادیر موقت درطول اجرای خط لوله
استفاده از کیت توسعه نرم‌افزار field("name") constant("val") variable("name")
Scope محلی برای سند فعلی جهانی سراسری به خط لوله و خط لوله‌های فرعی
مرجع تعریف‌نشده به absent ارزیابی می‌شود نامربوط خطای زمان اجرا تولید می‌کند

نمونه:

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")));
پایتون
from google.cloud.firestore_v1.pipeline_expressions import Field, Constant

pipeline = (
    client.pipeline()
    .collection("cities")
    .where(Field.of("name").equal(Constant.of("Toronto")))
)
رفتن
pipeline := client.Pipeline().Collection("cities").
	Where(firestore.FieldOf("name").Equal(firestore.ConstantOf("Toronto")))

مراحل

مراحل ورودی

مرحله ورودی نشان‌دهنده اولین مرحله از پُرسمان است. این فیلتر مجموعه اولیه اسنادی را که از آن‌ها پرس‌وجو می‌کنید تعریف می‌کند. برای عملیات Pipeline، این تا حد زیادی شبیه به پُرسمان‌های موجود است، که در آن اکثر پُرسمان‌ها با مرحله collection(...) یا collection_group(...) شروع می‌شوند. دو مرحله ورودی جدید عبارت‌اند از database() و documents(...) که database() امکان برگرداندن همه اسناد را در پایگاه داده فراهم می‌کند، درحالی‌که documents(...) عملکردی مشابه خواندن دسته‌ای دارد.

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();
پایتون
# 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()
)
رفتن
// 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
}

مانند همه مراحل دیگر، ترتیب نتایج حاصل از این مراحل ورودی پایدار نیست. اگر ترتیب خاصی لازم باشد، همیشه باید عملگر sort(...) اضافه شود.

مکان

مرحله where(...) به‌عنوان یک عملیات فیلتر استاندارد روی اسناد تولیدشده از مرحله قبلی عمل می‌کند و عمدتاً نحو «where» موجود برای پُرسمان‌های موجود را منعکس می‌کند. هر سندی که در آن عبارت داده‌شده به مقدار غیرtrue ارزیابی شود از اسناد برگردانده‌شده فیلتر می‌شود.

چند عبارت where(...) را می‌توان به‌هم زنجیر کرد و به‌عنوان عبارت and(...) عمل کرد. برای مثال، دو پُرسمان زیر ازنظر منطقی معادل هستند و می‌توانند به‌جای یکدیگر استفاده شوند.

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();
پایتون
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()
)
رفتن
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
}

انتخاب / افزودن و برداشتن فیلدها

select(...)، add_fields(...)، و remove_fields(...) همگی به شما امکان می‌دهند فیلدهای برگردانده‌شده از مرحله قبلی را اصلاح کنید. این سه نوع معمولاً به‌عنوان مراحل سبک فرافکنی شناخته می‌شوند.

select(...) و add_fields(...) به شما امکان می‌دهند نتیجه عبارت را برای نام فیلد ارائه‌شده توسط کاربر مشخص کنید. select(...) فقط اسناد دارای نام‌های فیلد مشخص‌شده را برمی‌گرداند، درحالی‌که add_fields(...) طرحواره مرحله قبلی را گسترش می‌دهد (احتمالاً مقادیر دارای نام‌های فیلد یکسان را رونویسی می‌کند).

remove_fields(...) امکان مشخص کردن مجموعه‌ای از فیلدها را برای حذف از مرحله قبلی فراهم می‌کند. مشخص کردن نام فیلدهایی که وجود ندارند، عملیاتی انجام نمی‌دهد.

بخش محدود کردن فیلدها برای برگرداندن را در زیر ببینید، اما به‌طور کلی استفاده از چنین مرحله‌ای برای محدود کردن نتیجه فقط به فیلدهای موردنیاز در کارخواه برای کاهش هزینه و تأخیر در اکثر پُرسمان‌ها مفید است.

مجموع / متمایز

مرحله aggregate(...) به شما امکان می‌دهد مجموعه‌ای از تجمیع‌ها را روی اسناد ورودی انجام دهید. به‌طور پیش‌فرض، همه اسناد باهم تجمیع می‌شوند، اما می‌توان آرگومان اختیاری grouping را ارائه کرد که به اسناد ورودی اجازه می‌دهد در دسته‌های مختلف تجمیع شوند.

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();
پایتون
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()
)
رفتن
snapshot := client.Pipeline().
	Collection("books").
	Aggregate(
		firestore.Accumulators(firestore.Average("rating").As("avg_rating")),
		firestore.WithAggregateGroups("genre"),
	).
	Execute(ctx)

وقتی groupings مشخص نشده باشد، این مرحله فقط یک سند تولید می‌کند، درغیراین‌صورت برای هر ترکیب منحصربه‌فرد از مقادیر groupings یک سند تولید خواهد شد.

مرحله distinct(...) یک اپراتور تجمیع ساده‌شده است که امکان تولید فقط groupings منحصربه‌فرد را بدون هیچ انباشتگری فراهم می‌کند. از همه جنبه‌های دیگر، رفتاری مشابه aggregate(...) دارد. مثال زیر نشان می‌دهد:

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();
پایتون
from google.cloud.firestore_v1.pipeline_expressions import Field

results = (
    client.pipeline()
    .collection("books")
    .distinct(Field.of("author").to_upper().as_("author"), "genre")
    .execute()
)
رفتن
snapshot := client.Pipeline().
	Collection("books").
	Distinct(firestore.Fields(
		firestore.ToUpper(firestore.FieldOf("author")).As("author"),
		firestore.FieldOf("genre"),
	)).
	Execute(ctx)

توابع

توابع واحد سازنده برای ایجاد عبارت‌ها و پُرسمان‌های پیچیده هستند. برای مشاهده فهرست کامل توابع به‌همراه مثال، به مرجع توابع مراجعه کنید. به‌عنوان یادآوری سریع، ساختار یک پُرسمان معمولی را درنظر بگیرید:

نمونه‌ای که مراحل و توابع را در پُرسمان نشان می‌دهد

بسیاری‌از مراحل عبارت‌هایی را می‌پذیرند که شامل یک یا چند تابع است. رایج‌ترین کاربرد تابع در مراحل where(...) و select(...) خواهد بود. دو نوع اصلی از تابع وجود دارد که باید با آن‌ها آشنا باشید:

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();
پایتون
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()
)
رفتن
// 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
}

محدودیت‌ها

در بیشتر موارد، نسخه Enterprise محدودیتی بر شکل پُرسمان اعمال نمی‌کند. به‌عبارت دیگر، به تعداد کمی از مقادیر در پُرسمان IN یا OR محدود نیستید. درعوض، دو محدودیت اصلی وجود دارد که باید از آن‌ها مطلع باشید:

  • مهلت: ۶۰ ثانیه (مشابه نسخه Standard).
  • استفاده از حافظه: محدودیت ۱۲۸ مبی‌بایت برای مقدار داده‌های تحقق‌یافته درطول اجرای پُرسمان.

خطاها

ممکن است به دلایل مختلفی با پُرسمان‌های ناموفق مواجه شوید. در اینجا پیوندی به خطاهای رایج و اقدام مرتبطی که می‌توانید انجام دهید آورده شده است:

کد خطا اکشن
DEADLINE_EXCEEDED پرس‌وجویی که اجرا می‌کنید از مهلت ۶۰ ثانیه‌ای فراتر می‌رود و به بهینه‌سازی بیشتری نیاز دارد. برای نکته‌ها، بخش عملکرد را ببینید. اگر نمی‌توانید علت ریشه‌ای مشکل را پیدا کنید، با تیم تماس بگیرید.
RESOURCE_EXHAUSTED پُرسمانی که اجرا می‌کنید از حد مجاز حافظه فراتر می‌رود و به بهینه‌سازی بیشتری نیاز دارد. برای نکته‌ها، بخش عملکرد را ببینید. اگر نمی‌توانید علت ریشه‌ای مشکل را پیدا کنید، با تیم تماس بگیرید.
INTERNAL برای دریافت پشتیبانی، با تیم تماس بگیرید.

عملکرد

پایگاه‌های داده نسخه Enterprise نیازی به وجود همیشگی نمایه ندارند. این یعنی پُرسمان می‌تواند درمقایسه با پُرسمان‌های موجود که به‌دلیل خطای نمایه گمشده FAILED_PRECONDITION بلافاصله ناموفق می‌شدند، تأخیر بیشتری نشان دهد. برای بهبود عملکرد عملیات Pipeline، می‌توانید چند مرحله را انجام دهید.

ایجاد نمایه‌ها

شاخص استفاده‌شده

«توضیح پُرسمان» به شما امکان می‌دهد تشخیص دهید که آیا پُرسمانتان توسط نمایه‌ای ارائه می‌شود یا به عملیات کم‌بازده‌تری مانند اسکن جدول برمی‌گردد. اگر پُرسمانتان به‌طور کامل از نمایه‌ای ارائه نمی‌شود، می‌توانید با دنبال کردن دستورالعمل‌ها نمایه‌ای ایجاد کنید.

درحال ایجاد نمایه‌ها

برای ایجاد نمایه‌ها، می‌توانید اسناد مدیریت نمایه موجود را دنبال کنید. قبل‌از ایجاد نمایه، با روال‌های مطلوب عمومی برای نمایه‌ها در Cloud Firestore آشنا شوید. برای اطمینان از اینکه پُرسمان شما می‌تواند از نمایه‌ها بهره ببرد، روال‌های مطلوب را برای ایجاد نمایه‌ها با فیلدها به‌ترتیب زیر دنبال کنید:

  1. همه فیلدهایی که در فیلترهای برابری استفاده خواهند شد (به هر ترتیبی)
  2. همه فیلدهایی که براساس آن‌ها مرتب‌سازی انجام می‌شود (به همان ترتیب)
  3. فیلدهایی که در فیلترهای محدوده یا نابرابری به‌ترتیب نزولی گزینش‌پذیری محدودیت پُرسمان استفاده خواهند شد

برای مثال، برای پُرسمان زیر،

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();
پایتون
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()
)
رفتن
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)

نمایه توصیه‌شده نمایه محدوده مجموعه در books برای (genre [...], published DESC, avg_rating DESC). است

تراکم نمایه

Cloud Firestore از نمایه‌های پراکنده و غیرپراکنده پشتیبانی می‌کند. برای اطلاعات بیشتر، تراکم نمایه را ببینید.

پُرسمان‌های پوشش‌داده‌شده + نمایه‌های ثانویه

Cloud Firestore می‌تواند از واکشی سند کامل صرف‌نظر کند و فقط نتایج را از نمایه برگرداند، اگر همه فیلدهای برگردانده‌شده در نمایه ثانویه وجود داشته باشند. این کار معمولاً منجر به بهبود قابل‌توجهی در تأخیر (و هزینه) می‌شود. بااستفاده از پُرسمان نمونه زیر:

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();
پایتون
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()
)
رفتن
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)

اگر پایگاه داده ازقبل نمایه محدوده مجموعه در books برای (category [...], title [...], author [...]) داشته باشد، می‌تواند از واکشی هرچیزی از خود اسناد اصلی اجتناب کند. در این مورد، ترتیب در نمایه اهمیتی ندارد، [...] برای نشان دادن این موضوع استفاده می‌شود.

محدود کردن فیلدها برای برگرداندن

به‌طور پیش‌فرض، پُرسمان Cloud Firestore همه فیلدهای سند را برمی‌گرداند، مشابه SELECT * در سیستم‌های رابطه‌ای. اما اگر برنامه شما فقط به زیرمجموعه‌ای از فیلدها نیاز دارد، می‌توان از مراحل select(...) یا restrict(...) برای انتقال این فیلتر به سمت سرور استفاده کرد. این کار هم اندازه پاسخ را کاهش می‌دهد (کاهش هزینه خروج شبکه) و هم تأخیر را بهبود می‌بخشد.

ابزارهای عیب‌یابی

توضیح پُرسمان

Query Explain به شما امکان می‌دهد سنجه‌های اجرا و جزئیات نمایه‌های استفاده‌شده را مشاهده کنید.

سنجه‌ها

عملیات خط لوله اگر کاملاً با سنجه‌های Cloud Firestore موجود ادغام شده باشد.

مشکلات شناخته‌شده / محدودیت‌ها

شاخص‌های تخصصی

عملیات خط لوله هنوز از array-contains و vector انواع نمایه موجود پشتیبانی نمی‌کند. به‌جای رد کردن این پُرسمان‌ها، Cloud Firestore تلاش می‌کند از نمایه‌های ascending و descending موجود دیگر استفاده کند. انتظار می‌رود که با چنین array_contains یا find_nearest، عبارت‌ها به‌دلیل این موضوع کندتر از معادل‌های موجودشان باشند.

پشتیبانی هم‌زمان و آفلاین

عملیات خط لوله قابلیت‌های هم‌زمان و آفلاین ندارد.

حالا چه می‌شود