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
C#
小茹
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);
索引注意事項
執行查詢前,請先參閱 [查詢][1] 和 Cloud Firestore [資料模型][2]的相關說明。
在 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 掃描的索引項目數量,但會篩除不相符的文件,因此傳回用戶端的文件數量會減少。
如要進一步瞭解如何建立有效率的索引,請參閱 [索引屬性][4]。
按照查詢限制選擇性的遞減順序排列欄位
為確保 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 一律會優先選擇索引欄位前置字元與查詢的 order by 子句相符的索引。如果將 experience 新增至 order by 子句,Cloud Firestore 會選取 (experience [...], salary [...]) 索引來計算查詢結果。由於 experience 沒有其他限制,Cloud Firestore 會先讀取 employees 集合的「所有」索引項目,然後套用 salary 篩選器,找出最終結果集。這表示系統仍會讀取不符合 salary 篩選條件的索引項目,進而增加查詢的延遲時間和費用。
定價
如果查詢在多個欄位使用範圍和不等式篩選器,則會根據讀取的文件和索引項目計費。
詳情請參閱 [定價][5] 頁面。
限制
除了 [查詢限制][6]之外,在多個欄位上使用範圍和不等式篩選器的查詢之前,請注意下列限制:
- 不支援對文件欄位使用範圍或不等式篩選器,且僅對文件索引鍵
(__name__)使用等式限制的查詢。 - Cloud Firestore 將範圍或不等式欄位的數量限制為 10 個。這是為了避免查詢執行費用過高。
後續步驟
- 瞭解如何 [最佳化查詢][3]。
- 進一步瞭解如何 [執行簡單和複合查詢][8]。
- 瞭解 [Cloud Firestore 如何使用索引][9]。
[1]: /docs/firestore/query-data/get-data [2]: /docs/firestore/data-model [3]: /docs/firestore/query-data/multiple-range-optimize-indexes [4]: /docs/firestore/concepts/index-overview#index_properties [5]: /docs/firestore/pricing [6]: /docs/firestore/query-data/queries#query_limitations [7]: https://en.wikipedia.org/wiki/Disjunctive_normal_form [8]: /docs/firestore/query-data/queries [9]: /docs/firestore/concepts/index-overview [10]: /docs/firestore/query-data/multiple-range-optimize-indexes