סקירה כללית של שאילתה עם מסנני טווח ואי-שוויון בכמה שדות

ב-Cloud Firestore יש תמיכה בשימוש במסנני טווחים ובמסנני אי-שוויון במספר שדות בשאילתה אחת. אפשר להשתמש בתנאי טווח ובתנאי אי-שוויון במספר שדות, ולפשט את פיתוח האפליקציה על ידי הענקת גישה להטמעת הלוגיקה שלאחר הסינון ל-Cloud Firestore.

מסנני טווחים ואי-שוויונים בכמה שדות

בשאילתה הבאה נעשה שימוש במסנני טווח של אוכלוסייה וצפיפות כדי להציג את כל הערים שבהן האוכלוסייה גדולה מ-1,000,000 איש והצפיפות היא פחות מ-10,000 איש ליחידת שטח.

גרסת אינטרנט 9 מודולרית

const q = query(
    collection(db, "cities"),
    where('population', '>', 1000000),
    where('density', '<', 10000),
  );

Swift

let query = db.collection("cities")
  .whereField("population", isGreaterThan: 1000000)
  .whereField("density", isLessThan: 10000)

Objective-C

FIRQuery *query =
 [[[[self.db collectionWithPath:@"cities"]
queryWhereField:@"population" isGreaterThan:@1000000]
   queryWhereField:@"density" isLessThan:@10000];

Java Android

Query query = db.collection("cities")
 .whereGreaterThan("population", 1000000)
 .whereLessThan("density", 10000);

Kotlin+KTX Android

val query = db.collection("cities")
 .whereGreaterThan("population", 1000000)
 .whereLessThan("density", 10000)

Go

   query := client.Collection("cities").
      Where("population", ">", 1000000).
      Where("density", "<", 10000)

Java

db.collection("cities")
  .whereGreaterThan("population", 1000000)
  .whereLessThan("density", 10000);

Node.js

db.collection("cities")
  .where('population', '>', 1000000),
  .where('density', '<', 10000)

Python

from google.cloud import firestore

db = firestore.Client()
query = db.collection("cities")
.where("population", ">", 1000000)
.where("density", "<", 10000)

PHP

$collection = $db->collection('samples/php/cities');
$chainedQuery = $collection
    ->where('population', '>', 1000000)
    ->where('density', '<', 10000);

C#‎

CollectionReference citiesRef = db.Collection("cities");
Query query = citiesRef
    .WhereGreaterThan("Population", 1000000)
    .WhereLessThan("Density", 10000);
QuerySnapshot querySnapshot = await query.GetSnapshotAsync();
foreach (DocumentSnapshot documentSnapshot in querySnapshot)
{
    var name = documentSnapshot.GetValue<string>("Name");
    var population = documentSnapshot.GetValue<int>("Population");
    var density = documentSnapshot.GetValue<int>("Density");
    Console.WriteLine($"City '{name}' returned by query. Population={population}; Density={density}");
}

Ruby

query = cities_ref.where("population", ">", "1000000")
                  .where("density", "<", 10000)

C++‎

CollectionReference cities_ref = db->Collection("cities");
Query query = cities_ref.WhereGreaterThan("population", FieldValue::Integer(1000000))
                       .WhereLessThan("density", FieldValue::Integer(10000));

Unity

CollectionReference citiesRef = db.Collection("cities");
Query query = citiesRef.WhereGreaterThan("population", 1000000)
                      .WhereLessThan("density", 10000);

Dart

final citiesRef = FirebaseFirestore.instance.collection('cities')
final query = citiesRef.where("population", isGreaterThan: 1000000)
                  .where("density", isLessThan: 10000);

שיקולים לגבי הוספה לאינדקס

לפני שמריצים את השאילתות, כדאי לקרוא על שאילתות ועל מודל הנתונים של Cloud Firestore.

ב-Cloud Firestore, התנאי ORDER BY בשאילתה קובע באילו אינדקסים אפשר להשתמש כדי להציג את השאילתה. לדוגמה, כדי להשתמש בשאילתה ORDER BY a ASC, b ASC נדרש אינדקס מורכב בשדות a ASC, b ASC.

כדי לשפר את הביצועים והעלות של שאילתות Cloud Firestore, צריך לבצע אופטימיזציה של סדר השדות במדד. כדי לעשות זאת, צריך לוודא שהאינדקס מסודר משמאל לימין, כך שהשאילתה תתמצת למערך נתונים שימנע סריקת רשומות מיותרות באינדקס.

נניח שאתם רוצים לחפש באוסף של עובדים ולמצוא עובדים בארצות הברית שהמשכורת שלהם גבוהה מ-100,000 $ומספר שנות הניסיון שלהם גדול מאפס. על סמך ההבנה שלכם של מערך הנתונים, אתם יודעים שהאילוץ על השכר סלקטיבי יותר מהאילוץ על ניסיון העבודה. האינדקס האידיאלי שיצמצם את מספר סריקות האינדקס הוא (salary [...], experience [...]). לכן, השאילתה שתהיה מהירה וחסכונית תסדר את salary לפני experience ותראה כך:

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .whereGreaterThan("experience", 0)
  .orderBy("salary")
  .orderBy("experience");

Node.js

db.collection("employees")
  .where("salary", ">", 100000)
  .where("experience", ">", 0)
  .orderBy("salary")
  .orderBy("experience");

Python

db.collection("employees")
  .where("salary", ">", 100000)
  .where("experience", ">", 0)
  .order_by("salary")
  .order_by("experience");

שיטות מומלצות לאופטימיזציה של אינדקסים

כשמבצעים אופטימיזציה של אינדקסים, כדאי לזכור את השיטות המומלצות הבאות.

סדר שדות האינדקס לפי שוויות, ואחריהם טווח הבחירה או שדה אי-השוויון הכי סלקטיבי

Cloud Firestore משתמש בשדות שמשמאל ביותר באינדקס מורכב כדי לעמוד באילוצי השוויון ובאילוץ הטווח או אי-השוויון, אם קיים, בשדה הראשון של השאילתה orderBy(). האילוצים האלה יכולים לצמצם את מספר הרשומות במדד ש-Cloud Firestore סורק. Cloud Firestore משתמש בשאר השדות של האינדקס כדי לעמוד באילוצים אחרים של טווח או אי-שוויון בשאילתה. האילוצים האלה לא מפחיתים את מספר הרשומות באינדקס ש-Cloud Firestore סורק, אבל הם מסננים מסמכים שלא תואמים, כך שמספר המסמכים שמוחזרים ללקוחות מצטמצם.

מידע נוסף על יצירת אינדקסים יעילים זמין במאמר מאפייני אינדקס.

מיון השדות לפי סדר יורד של סלקטיביות האילוצים של השאילתה

כדי לוודא ש-Cloud Firestore יבחר את האינדקס האופטימלי לשאילתה, צריך לציין תנאי orderBy() שמסדר את השדות בסדר יורד של סלקטיביות האילוצים של השאילתה. ככל שהסלקטיביות גבוהה יותר, כך מתבצעות התאמות לקבוצת משנה קטנה יותר של מסמכים, וככל שהסלקטיביות נמוכה יותר, כך מתבצעות התאמות לקבוצת משנה גדולה יותר של מסמכים. חשוב לוודא שבוחרים שדות טווח או שדות אי-שוויון עם סלקטיביות גבוהה יותר בשלב מוקדם יותר בסדר האינדקס, בהשוואה לשדות עם סלקטיביות נמוכה יותר.

כדי לצמצם את מספר המסמכים ש-Cloud Firestore סורק ומחזיר ברשת, תמיד צריך למיין את השדות לפי הסדר יורד של סלקטיביות האילוצים של השאילתה. אם קבוצת התוצאות לא מסודרת לפי הסדר הנדרש, וצפויה להיות קטנה, תוכלו להטמיע לוגיקה בצד הלקוח כדי לסדר אותה מחדש בהתאם לציפיות שלכם.

לדוגמה, נניח שאתם רוצים לחפש באוסף של עובדים כדי למצוא עובדים בארצות הברית שהמשכורת שלהם גבוהה מ-100,000$, ולסדר את התוצאות לפי שנות הניסיון של העובד. אם אתם צופים שרק למספר קטן של עובדים יהיו משכורות של יותר מ-400,000 ש"ח, הדרך היעילה ביותר לכתוב את השאילתה היא כך:

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .orderBy("salary")
  .get()
  .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
        @Override
        public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
          // Order results by `experience`
        }
    });;

Node.js

const querySnapshot = await db.collection('employees')
                              .where("salary", ">", 100000)
                              .orderBy("salary")
                              .get();

// Order results by `experience`

Python

results = db.collection("employees")
            .where("salary", ">", 100000)
            .order_by("salary")
            .stream()

// Order results by `experience`

הוספת סדר ל-experience לשאילתה תניב את אותה קבוצה של מסמכים ותבטל את הצורך בסדר מחדש של התוצאות בלקוחות, אבל השאילתה עשויה לקרוא הרבה יותר רשומות מיותרות באינדקס בהשוואה לשאילתה הקודמת. הסיבה לכך היא ש-Cloud Firestore תמיד מעדיף אינדקס שהתחילית של שדות האינדקס שלו תואמת לתנאי order by בשאילתה. אם הוספת את experience לתנאי order by, הפונקציה Cloud Firestore תבחר את האינדקס (experience [...], salary [...]) לצורך חישוב תוצאות השאילתה. מאחר שאין אילוצים אחרים על experience, הפונקציה Cloud Firestore תקריא את כל הרשומות באינדקס של האוסף employees לפני החלת המסנן salary כדי למצוא את קבוצת התוצאות הסופית. המשמעות היא שעדיין מתבצעת קריאה של רשומות אינדקס שלא עומדות בקריטריונים של המסנן salary, וכך משך האחזור והעלות של השאילתה עולים.

תמחור

חיפושים עם מסנני טווח ואי-שוויון בכמה שדות מחויבים על סמך מספר המסמכים שנקראו ומספר הרשומות שנוספו לאינדקס.

מידע מפורט זמין בדף Pricing.

מגבלות

בנוסף למגבלות על שאילתות, חשוב לשים לב למגבלות הבאות לפני שמשתמשים בשאילתות עם מסנני טווחים ויחסי אי-שוויון במספר שדות:

  • אין תמיכה בשאילתות עם מסנני טווח או אי-שוויון בשדות המסמך, ורק באילוצים של שוויון במפתח המסמך (__name__).
  • Cloud Firestore מגביל את מספר השדות של טווחים או אי-שוויונות ל-10. המטרה היא למנוע הוצאות יקרות מדי על הרצת שאילתות.

המאמרים הבאים