總覽:在多個欄位使用範圍和不等式篩選器進行查詢

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 美元的美國員工,而且工作年資大於 0。根據您對資料集的瞭解,您知道薪資限制比經驗限制更具選擇性。(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 美元的美國員工,並依員工的年資排序結果。如果您預期只有少數員工的薪資超過 $100,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 一律會優先採用索引欄位前置字串與查詢的排序依據子句相符的索引。如果 experience 已新增至 order by 子句,Cloud Firestore 就會選取 (experience [...], salary [...]) 索引來計算查詢結果。由於 experience 沒有其他限制條件,Cloud Firestore 會先讀取 employees 集合的「所有」索引項目,再套用 salary 篩選器來找出最終結果集。這表示系統仍會讀取不符合 salary 篩選條件的索引項目,因此會增加查詢的延遲時間和成本。

定價

針對多個欄位套用範圍和不等式篩選器的查詢,將依據讀取的文件和讀取的索引項目計費。

詳情請參閱「定價」頁面。

限制

除了查詢限制之外,請注意以下限制,再使用含有範圍和不等式篩選條件的查詢,針對多個欄位進行查詢:

  • 系統不支援針對文件欄位使用範圍或不等式篩選器,以及僅針對文件索引鍵 (__name__) 使用等式限制的查詢。
  • Cloud Firestore 會將範圍或不等式欄位數量限制在 10 個。以免查詢費用過高的執行。

後續步驟