为啥这个 firestore 查询需要索引?

Posted

技术标签:

【中文标题】为啥这个 firestore 查询需要索引?【英文标题】:Why does this firestore query require an index?为什么这个 firestore 查询需要索引? 【发布时间】:2019-05-16 08:11:40 【问题描述】:

我有一个带有相等运算符的where() 方法和一个orderBy() 方法的查询,但我不知道为什么它需要索引。 where 方法检查对象(地图)中的值,并且使用数字进行排序。

文档说

如果您有一个具有范围比较(、>=)的过滤器,则您的第一个排序必须在同一字段中

所以我认为平等过滤器会很好。

这是我的查询代码:

this.afs.collection('posts').ref
.where('tags.' + this.courseID,'==',true)
.orderBy("votes")
.limit(5)
.get().then(snap => 
  snap.forEach(doc => 
    console.log(doc.data());
  );
);

这是一个数据库结构的例子

【问题讨论】:

正如 Alex 回答的:Firestore 自动为每个单独的字段创建索引。但是您的查询需要'tags.' + this.courseID votes 上的复合索引,这不是自动创建的。请注意,您可以通过using an array and the array-contains operator 简化您的查询。除了更简单之外,这可能不需要额外的索引。 @FrankvanPuffelen 很棒的想法。 array-contains 确实需要一个索引,但只有一个,而我需要一个新的索引来为每个 courseID 设置一个相等的索引。谢谢! 【参考方案1】:

为什么这个 Firestore 查询需要索引?

您可能已经注意到,Cloud Firestore 中的查询非常快,这是因为 Firestore 会自动为您在文档中的任何字段创建索引。因此,当您简单地使用范围比较进行过滤时,Firestore 会自动创建所需的索引。如果您还尝试对结果进行排序,则需要另一个索引。这种索引不是自动创建的。您应该自己创建它。这可以通过在您的 Firebase Console 中手动创建来完成,或者您会在日志中找到一条听起来像这样的消息:

FAILED_PRECONDITION: The query requires an index. You can create it here: ...

您只需单击该链接或将 URL 复制并粘贴到网络浏览器中,您的索引就会自动创建。

所以 Firestore 需要一个索引,以便您可以进行非常快速的查询。

【讨论】:

但是在集合不断更新并且新文档一直在添加的情况下会发生什么?我是否必须一次又一次地重建索引,或者一旦我构建它(现在集合中只有 5 个文档,用于测试/开发),它会在以后在生产模式下自动扩展它以获取更多文档? @Devashish 创建索引后,无需执行任何操作。它适用于任意数量的文档。 在新版云火库中找不到创建索引的链接。我必须从 firebase 控制台手动构建索引。我的错误仅显示“错误:[cloud_firestore/failed-precondition] 操作被拒绝,因为系统未处于操作执行所需的状态。如果执行查询,请确保已通过 Firebase 控制台对其进行索引。”。如何解决这个问题? @RachitRawat 正如警告消息所述,您很可能应该直接在 Firebase 控制台中添加索引。 但是我有很多索引需要构建。是否可以从某个地方获取此链接以简化流程?【参考方案2】:

索引只是数据库清单或记录在哪里。每个索引都是特定事物的特定清单——例如,集合中有多少 propertyX 字段以及它们的值是什么,已排序(它们已排序这一事实至关重要)。

如果此清单不存在,要查询 propertyXsomeValue 的文档,机器必须遍历整个集合以确定 (1) 哪些文档包含 propertyX 和 (2) 哪些文档包含propertyX 等于someValue。通过保留查询属性的清单(或索引),当对propertyX 执行查询时,机器可以直接进入propertyX 索引并收集所有等于someValue 的文档的位置,然后获取那些集合中的文档并返回它们。机器不仅不需要接触集合就知道文档在哪里,甚至不需要遍历整个索引,因为它总是有序的。

索引是集合大小对 Firestore 查询性能没有影响的原因,也是我们只需要为曾经查询过的属性编制索引的原因。

【讨论】:

以上是关于为啥这个 firestore 查询需要索引?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过在 Firestore 中的查询从索引中获取多个文档到其他索引

为啥我在 Flutter 中使用 Firestore 中的 foreach 方法后得到空值?

为啥 MySQL 中的这个查询不使用索引?

为啥这个查询使用 where 而不是索引?

mysql查询in为啥用不上索引

Firestore 索引错误