“对多个字段使用范围和不等式过滤条件的查询”概览
Firestore 支持在单个查询中对多个字段使用范围和不等式过滤条件。您现在可以将范围和不等式条件应用于多个字段,并通过将过滤后逻辑的实现委托给 Firestore 来简化应用开发。
对多个字段使用的范围和不等式过滤条件
以下查询通过对年龄 (age) 和身高 (height) 使用范围过滤条件,返回年龄超过 35 岁且身高在 60 到 70 之间的所有用户。
Web v9 模块化库
const q = query(
collection(db, "users"),
where('age', '>', 35),
where('height', '>', 60),
where('height', '<', 70)
);
Swift
let query = db.collection("users")
.whereField("age", isGreaterThan: 35)
.whereField("height", isGreaterThan: 60)
.whereField("height", isLessThan: 70)
Objective-C
FIRQuery *query =
[[[[self.db collectionWithPath:@"users"]
queryWhereField:@"age" isGreaterThan:@35]
queryWhereField:@"height" isGreaterThan:@60]
queryWhereField:@"height" isLessThan:@70];
Java Android
Query query = db.collection("users")
.whereGreaterThan("age", 35)
.whereGreaterThan("height", 60)
.whereLessThan("height", 70);
Kotlin+KTX Android
val query = db.collection("users")
.whereGreaterThan("age", 35)
.whereGreaterThan("height", 60)
.whereLessThan("height", 70)
Java
db.collection("users")
.whereGreaterThan("age", 35)
.whereGreaterThan("height", 60)
.whereLessThan("height", 70);
Node.js
db.collection("users")
.where('age', '>', 35),
.where('height', '>', 60),
.where('height', '<', 70)
索引编制注意事项
在开始运行查询之前,请确保您已阅读有关查询和 Firestore 数据模型的内容。
在 Firestore 中,查询的 ORDER BY
子句决定了可以使用哪些索引来处理查询。例如,ORDER BY a ASC, b ASC
查询需要使用一个基于 a ASC, b ASC
字段的复合索引。
为了优化 Firestore 查询的性能和费用,您应该优化索引中字段的顺序。为此,您应确保按如下方式将索引从左到右排序:即要使得查询能够在提取到某个数据集后,便不再继续扫描无关的索引条目。
假设您想搜索一组员工,并找到薪水超过 10 万美元且工作经验年限超过 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");
索引优化最佳实践
优化索引时,请遵循以下最佳实践。
先按等式过滤条件对索引字段进行排序,然后按严苛程度最高的范围或不等式字段对索引字段进行排序
Firestore 使用复合索引的最左边的字段来满足 orderBy()
查询的第一个字段的相等性限制以及范围或不等性限制(如果有)。这些限制条件可以减少 Firestore 扫描的索引条目数量。Firestore 使用索引的剩余字段来满足查询的其他范围约束或不等式约束。这些限制条件不会减少 Firestore 扫描的索引条目数,但会过滤掉不匹配的文档,以减少返回给客户端的文档数。
如需详细了解如何创建高效索引,请参阅完美索引的定义。
将字段按查询限制条件的严苛程度降序排列
为了确保 Firestore 为您的查询选择最佳索引,请指定 orderBy()
子句,以按查询限制条件选择性降序对字段进行排序。严苛程度越高,匹配的文档子集就越小;相反,严苛程度越低,匹配的文档子集就越大。确保在索引排序中,先选择严苛程度更高的范围或不等式字段,后选择严苛程度更低的字段。
为了尽可能减少 Firestore 通过网络扫描和返回的文档数量,您应始终按照查询限制条件选择性的降序对字段进行排序。如果结果集未按所需顺序排序,并且预计结果集较小,则您可以实现客户端逻辑来按所需顺序对其重新排序。
例如,假设您想搜索一组员工,找到薪水超过 10 万美元的员工,并将结果按员工的工作经验年限进行排序。如果您预计只有少数员工的薪水会超过 10 万美元,那么可按如下所示编写最高效的查询:
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
排序会产生相同的文档集,并且无需在客户端对结果进行重新排序,但该查询可能会比之前的查询读取更多无关的索引条目。这是因为 Firestore 始终会优先选择索引字段前缀与查询的 order by 子句匹配的索引。如果将 experience
添加到了 order by 子句中,Firestore 将选择 (experience [...], salary [...])
索引来计算查询结果。由于 experience
没有其他限制,因此 Firestore 会先读取 employees
集合的所有索引条目,然后再应用 salary
过滤条件来查找最终结果集。这意味着,不满足 salary
过滤条件的索引条目仍会被读取,从而导致查询的延迟时间和费用增加。
价格
对多个字段使用范围和不等式过滤条件的查询是根据所读取的文档数和索引条目数来收费的。
如需了解详细信息,请参阅价格页面。
限制
除了查询限制之外,在使用对多个字段使用范围和不等式过滤条件的查询之前,还应注意以下限制:
- 不支持对文档字段使用范围或不等式过滤条件的查询,也不支持对文档键
(__name__)
仅使用等式限制条件的查询。 - Firestore 将范围或不等式字段的数量限制为 10。这样做是为了防止查询的运行开销过高。
后续步骤
- 了解如何优化查询。
- 详细了解如何执行简单查询和复合查询。
- 了解 Firestore 如何使用索引。