针对多个字段使用范围和不等式过滤条件的查询概览

Cloud Firestore 支持在单个查询中对多个字段使用范围和不等式过滤条件。您现在可以将范围和不等式条件应用于多个字段,并通过将过滤后逻辑的实现委托给 Cloud Firestore 来简化应用开发。

针对多个字段的范围和不等式过滤器

以下查询使用年龄和身高的范围过滤条件,返回年龄大于 35 且身高介于 60 到 70 之间的所有用户。

Web 版本 9 模块化

  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)

索引编制注意事项

在开始运行查询之前,请确保您已阅读有关查询和 Cloud Firestore 数据模型的内容。

在 Cloud Firestore 中,查询的 ORDER BY 子句决定了可以使用哪些索引来处理查询。例如,ORDER BY a ASC, b ASC 查询需要 a ASC, b ASC 字段的复合索引。

为了优化 Cloud Firestore 查询的性能和费用,您应该优化索引中字段的顺序。为此,您应确保索引按从左到右的顺序排列,以使查询提取为一个数据集,从而防止扫描无关索引条目。

假设您要搜索员工集合,并查找薪资超过 100000 且经验年限大于 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 的员工,并按员工的工作年限对结果进行排序。如果您预计只有少数员工的薪资会超过 100000,那么最有效的查询编写方式如下所示:

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 过滤条件的索引条目,从而增加查询的延迟时间和费用。

价格

对多个字段使用范围和不等式过滤条件的查询根据读取的文档和索引条目数计费。

如需了解详情,请参阅价格页面。

限制

除了查询限制之外,在对多个字段使用范围和不等式过滤条件的查询之前,请注意以下限制:

  • 不支持对文档字段应用范围或不等式过滤条件,而对文档键 (__name__) 仅应用等式限制的查询。
  • Cloud Firestore 将范围或不等式字段的数量限制为 10。这是为了防止查询运行成本过高。

后续步骤