الخلفية
Pipeline Queries هي واجهة طلبات بحث جديدة في Firestore. توفّر هذه اللغة وظائف بحث متقدّمة، بما في ذلك عبارات معقّدة. ويضيف أيضًا دعمًا للعديد من الدوال الجديدة، مثل min, max, substring, regex_match وarray_contains_all.
باستخدام "طلبات البحث عبر خطوط الإنتاج"، يصبح إنشاء الفهرس اختياريًا تمامًا، ما يؤدي إلى تبسيط عملية تطوير طلبات البحث الجديدة. تزيل "طلبات البحث في سلسلة المعالجة" أيضًا العديد من القيود المفروضة على شكل طلب البحث، ما يتيح لك تحديد طلبات بحث كبيرة in أو or.
البدء
لتثبيت حِزم SDK الخاصة بالعميل وإعدادها، يُرجى الرجوع إلى التعليمات الواردة في دليل البدء.
البنية
تقدّم الأقسام التالية نظرة عامة على بنية طلبات البحث في Pipeline.
المفاهيم
أحد الاختلافات الملحوظة في "طلبات البحث المتسلسلة" هو تقديم ترتيب "المرحلة" الصريح. ويتيح ذلك إمكانية التعبير عن استعلامات أكثر تعقيدًا. ومع ذلك، يشكّل ذلك انحرافًا ملحوظًا عن واجهة طلب البحث الحالية التي كان ترتيب المراحل فيها ضمنيًا. إليك مثالاً على طلب بحث في 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);
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) )
الإعداد
تتضمّن "طلبات بحث المسار" بنية مألوفة جدًا مستمدة من طلبات البحث الحالية 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();
Python
firestore_client = firestore.client(default_app, "your-new-enterprise-database") pipeline = firestore_client.pipeline()
البنية
هناك بعض المصطلحات المهمة التي يجب فهمها عند إنشاء "طلبات بحث في مسار البيانات": المراحل والعبارات والدوال.

المراحل: قد تتألف عملية البيع من مرحلة واحدة أو أكثر. من الناحية المنطقية، تمثّل هذه المراحل سلسلة الخطوات التي يتم اتّخاذها لتنفيذ طلب البحث. ملاحظة: من الناحية العملية، قد يتم تنفيذ المراحل بترتيب مختلف لتحسين الأداء. ومع ذلك، لا يؤدي ذلك إلى تعديل الغرض من الطلب أو صحته.
التعبيرات: غالبًا ما تقبل المراحل تعبيرًا يتيح لك التعبير عن طلبات بحث أكثر تعقيدًا. قد تكون الصيغة بسيطة وتتألف من دالة واحدة مثل eq("a", 1). يمكنك أيضًا التعبير عن صيغ أكثر تعقيدًا من خلال تضمين صيغ مثل and(eq("a", 1), eq("b", 2)).
المراجع الخاصة بالحقول مقابل المراجع الثابتة
تتيح طلبات البحث في مسار البيانات استخدام عبارات معقّدة. وبالتالي، قد يكون من الضروري التمييز بين ما إذا كانت القيمة تمثّل حقل أو ثابت. راجع المثال التالي:
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"))) )
المسارح
مراحل الإدخال
تمثّل مرحلة الإدخال المرحلة الأولى من طلب البحث. تحدّد هذه السمة المجموعة الأولية من المستندات التي تبحث فيها. بالنسبة إلى استعلامات مسار الإحالة الناجحة، يشبه ذلك إلى حد كبير الاستعلامات الحالية، حيث تبدأ معظم الاستعلامات بالمرحلة 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();
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() )
كما هو الحال مع جميع المراحل الأخرى، لا يكون ترتيب النتائج من مراحل الإدخال هذه ثابتًا. يجب دائمًا إضافة عامل التشغيل 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();
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_fields(...) وremove_fields(...) تعديل الحقول التي يتم عرضها من مرحلة سابقة. ويُشار إلى هذه المراحل الثلاث بشكل عام باسم مراحل العرض.
يتيح لك select(...) وadd_fields(...) تحديد نتيجة تعبير لاسم حقل يوفّره المستخدم. سيؤدي التعبير الذي ينتج عنه خطأ إلى ظهور القيمة null. لن تعرض 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();
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، ستنتج هذه المرحلة مستندًا واحدًا فقط، وإلا سيتم إنشاء مستند لكل مجموعة فريدة من قيم 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();
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() )
الدوال
الدوال هي لبنة أساسية لإنشاء التعبيرات وطلبات البحث المعقّدة. للحصول على قائمة كاملة بالدوال مع أمثلة، يُرجى الرجوع إلى مرجع الدوال. كتذكير سريع، إليك بنية طلب البحث العادي:

تقبل العديد من المراحل عبارات تحتوي على دالة واحدة أو أكثر. سيتم العثور على الاستخدام الأكثر شيوعًا للدالة في مرحلتَي 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();
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() )
الحدود
في معظم الحالات، لا يفرض إصدار Enterprise قيودًا على شكل طلب البحث. بعبارة أخرى، لا يقتصر الأمر على عدد صغير من القيم في طلب بحث IN أو OR. بدلاً من ذلك، هناك حدّان أساسيان يجب الانتباه إليهما:
- الموعد النهائي: 60 ثانية (كما هو الحال في الإصدار Standard).
- استخدام الذاكرة: حدّ يبلغ 128 ميغابايت على كمية البيانات المادية أثناء تنفيذ طلب البحث
الأخطاء
قد تواجه طلبات بحث غير ناجحة لعدة أسباب. إليك رابط يؤدي إلى الأخطاء الشائعة والإجراءات المرتبطة التي يمكنك اتّخاذها:
| رمز الخطأ | الإجراء |
DEADLINE_EXCEEDED
|
يتجاوز طلب البحث الذي تنفّذه مهلة 60 ثانية ويتطلّب تحسينًا إضافيًا. يُرجى الاطّلاع على قسم "الأداء" للحصول على نصائح. إذا لم تتمكّن من تحديد السبب الجذري للمشكلة، تواصَل مع الفريق. |
RESOURCE_EXHAUSTED
|
يتجاوز طلب البحث الذي تنفّذه حدود الذاكرة ويتطلّب تحسينًا إضافيًا. يُرجى الاطّلاع على قسم "الأداء" للحصول على نصائح. إذا لم تتمكّن من تحديد السبب الجذري للمشكلة، تواصَل مع الفريق. |
INTERNAL
|
التواصل مع الفريق للحصول على الدعم |
الأداء
على عكس طلبات البحث الحالية، لا تتطلّب "طلبات البحث المتسلسلة" توفّر فهرس دائمًا. وهذا يعني أنّ طلب البحث يمكن أن يستغرق وقتًا أطول مقارنةً بطلبات البحث الحالية التي كانت ستتعذّر على الفور بسبب خطأ FAILED_PRECONDITION في الفهرس غير المتوفّر. لتحسين أداء "طلبات البحث المتسلسلة"، يمكنك اتّخاذ بعض الخطوات.
إنشاء الفهارس
الفهرس المستخدَم
تتيح لك ميزة "شرح طلب البحث" تحديد ما إذا كان طلب البحث يتم عرضه من خلال فهرس أو الرجوع إلى عملية أقل كفاءة، مثل فحص الجدول. إذا لم يتم عرض طلب البحث بالكامل من فهرس، يمكنك إنشاء فهرس باتّباع التعليمات.
إنشاء الفهارس
يمكنك اتّباع مستندات إدارة الفهرس الحالية لإنشاء الفهارس. قبل إنشاء فهرس، يُرجى الاطّلاع على أفضل الممارسات العامة المتعلّقة بالفهارس في Firestore. لضمان إمكانية استخدام الفهارس في طلب البحث، اتّبِع أفضل الممارسات لإنشاء فهارس تتضمّن حقولاً بالترتيب التالي:
- جميع الحقول التي سيتم استخدامها في فلاتر المساواة (بأي ترتيب)
- جميع الحقول التي سيتم ترتيبها (بالترتيب نفسه)
- الحقول التي سيتم استخدامها في فلاتر النطاق أو عدم المساواة بترتيب تنازلي حسب اختيارية قيود الطلب
على سبيل المثال، بالنسبة إلى طلب البحث التالي،
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() )
الفهرس المقترَح هو فهرس نطاق مجموعة على books لـ (genre [...], published DESC, avg_rating DESC).
كثافة الفهرس
تتيح Cloud Firestore استخدام فهارس متفرقة وغير متفرقة. لمزيد من المعلومات، اطّلِع على كثافة الفهرسة.
طلبات البحث المغطّاة والفهارس الثانوية
يمكن أن تتخطّى 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();
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() )
إذا كانت قاعدة البيانات تتضمّن فهرس نطاق مجموعة على books لـ (category [...], title [...], author [...])، يمكنها تجنُّب جلب أي بيانات من المستندات الرئيسية نفسها. في هذه الحالة، لا يهم الترتيب في الفهرس، ويتم استخدام [...] للإشارة إلى ذلك.
تقييد الحقول المطلوب عرضها
تعرض طلبات بحث Firestore تلقائيًا جميع الحقول في المستند، وهو ما يشبه SELECT * في الأنظمة التقليدية. إذا كان تطبيقك يحتاج فقط إلى مجموعة فرعية من الحقول، يمكن استخدام مرحلتَي select(...) أو restrict(...) لإجراء هذه الفلترة من جهة الخادم. سيؤدي ذلك إلى تقليل حجم الرد (ما يؤدي إلى خفض تكلفة نقل البيانات خارج الشبكة) وتحسين وقت الاستجابة.
أدوات تحرّي الخلل وإصلاحه
شرح طلب البحث
تتيح لك ميزة "شرح طلب البحث" إمكانية الاطّلاع على مقاييس التنفيذ وتفاصيل حول الفهارس المستخدَمة.
المقاييس
تتكامل طلبات بحث Pipeline بالكامل مع مقاييس Firestore الحالية.
المشاكل والقيود المعروفة
الفهارس المتخصّصة
لا تتيح طلبات البحث في مسار البيانات بعد array-contains وvector أنواع الفهرس الحالية. بدلاً من رفض طلبات البحث هذه، ستحاول Firestore استخدام فهارس ascending وdescending أخرى حالية. من المتوقّع أن تكون طلبات البحث في Pipeline التي تتضمّن تعبيرات array_contains أو find_nearest أبطأ من نظيراتها الحالية خلال المعاينة الخاصة بسبب ذلك.
الحدود الفاصلة للصفحات
لا تتوفّر إمكانية تقسيم مجموعة النتائج إلى صفحات بسهولة خلال المعاينة الخاصة. يمكن حلّ هذه المشكلة من خلال ربط مراحل where(...) وsort(...) المكافئة كما هو موضّح أدناه.
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()) )
التوافق مع المحاكي
لا يتيح المحاكي طلبات بحث Pipeline بعد.
التوافق مع ميزة "التعاون في الوقت الفعلي" و"التعديل بلا إنترنت"
لا تتوفّر إمكانات الوقت الفعلي والتعديل بلا إنترنت في طلبات البحث في مسار العرض بعد.
الخطوات التالية
- ابدأ باستكشاف المستندات المرجعية الخاصة بالدوال والمراحل.