如何在 Firebase 云 Firestore 中查询一个字段然后按另一个字段排序?

Posted

技术标签:

【中文标题】如何在 Firebase 云 Firestore 中查询一个字段然后按另一个字段排序?【英文标题】:How to query one field then order by another one in Firebase cloud Firestore? 【发布时间】:2018-04-14 10:15:16 【问题描述】:

我正在努力在 firebase cloud firestore 中进行(不是那么)复杂的查询。

我只需要获取所有文档whereid 字段== 给定的ID。

然后按date 对结果进行排序,并限制为 10 个结果。

这就是我现在的情况

db.firestore().collection('comments')
        .where("postId",'==',idOfThePost)
        .orderBy('date','asc').limit(10).get().then( snapshot => 
           //Nothing happens and the request wasn't even been executed
         )

只有当我不使用 orderBy 查询时我才能得到结果,但我必须根据我的应用程序的需要处理这种排序。

有人可以帮我解决这个问题吗?

谢谢

【问题讨论】:

这是idOfThePost的唯一ID吗? 实际上它是每个帖子的唯一ID,但是相关帖子的每个评论都有一个名为 postId 的字段来标识它所属的帖子。如此多的 cmets 共享相同的 postId 值。 你如何保存你的约会? datenum 格式Date.now() 的基本字段。每个文档中有一个日期字段postIdcomment 尝试发送服务器时间戳表单sdk并检查firebase.firestore.FieldValue.serverTimestamp() 【参考方案1】:

您可以通过在 Firestore 中创建索引来做到这一点。

索引的第一个字段应该是相等字段,索引的第二个字段应该是 order by 字段。

鉴于您的问题,您需要以下索引:

first field: postId, 'asc'
second field: date, 'asc'

【讨论】:

首先,谢谢你,你的答案是一个!如果有人第一次使用索引,请注意在代码中使用相同的顺序。例如: postId 是 "==" 条件,所以你没有使用排序,但是使用 orderBy("data", "asc"),你必须让 "asc" 排序。如果你想要一个“desc”排序,你必须为“desc”创建索引。【参考方案2】:

请查看doc。它说

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

你可以试试这个代码

db.firestore().collection('comments')
    .where("postId",'==',idOfThePost)
    .orderBy('postId')
    .orderBy('date','asc').limit(10).get().then( snapshot => 
       .....
     )

【讨论】:

我确实阅读了文档并且我已经尝试过但没有成功。并且文档说 range comparison 但是 == 不是范围比较运算符,因此文档的这一部分不适用于 == 。我说的对吗? == 不是范围比较。【参考方案3】:

我的解决方法

如果您在谷歌上搜索此内容,您可能已经意识到传统上无法做到这一点。根据您的问题,虽然可能有一些可行的解决方法,但我刚刚完成了这个。

场景

我们有一个应用程序,其中的帖子出现在提要中(有点像 Reddit),每个帖子都有一个算法得分“分数”,我们需要一种方法来获取 12-24 小时前的“热门帖子”。尝试按“分数”排序的查询,其中时间戳使用 > 和

解决方案

我们最终做的是使用作为数组的第二个字段,因为您可以对数组包含和降序进行复合查询。在发布帖子时,我们知道当前时间,假设距离服务器纪元(即floor(serverTime/60.0/60.0))是 10000 小时。我们将创建一个名为 arrayOfHoursWhenPostIsTwelveToTwentyFourHoursOld 的数组,并在该数组中填充以下值:

int hourOffset = 12;
while (hourOffset <= 24) 
    [arrayOfHoursWhenPostIsTwelveToTwentyFourHoursOld addObject:@(currentHour+hourOffset)];
    hourOffset++;

然后,在发布帖子时,我们将该数组存储在字段 hoursWhenPostIsTwelveToTwentyFourHoursOld

那么,如果自发布帖子以来已经过了 13 小时(帖子发布时间是 10000 小时),那么当前时间将是 10013,因此我们可以使用数组包含查询来查看我们的数组是否包含值10013,同时还按算法分数排序

像这样:

FIRFirestore *firestore = [Server sharedFirestore];
FIRCollectionReference *collection = [firestore collectionWithPath:@"Posts"];
FIRQuery *query = [collection queryOrderedByField:@"postsAlgorithmScore" descending:YES];
query = [query queryWhereField:@"hoursWhenPostIsTwelveToTwentyFourHoursOld" arrayContains:@(currentHour)];
query = [query queryLimitedTo:numberToLoad];

快完成了

上面的代码一开始不会正常运行,因为它使用的是复合索引查询,所以我们不得不在firebase中创建一个复合索引查询,最简单的方法是运行查询然后查看错误日志和 firebase SDK 将为您生成一个链接,您可以导航到该链接,它会自动为您的数据库生成复合索引,否则您可以导航到 firebase>database>index>compound>new 并使用自己构建它hoursWhenTwelveToTwentyFourHoursOld: Arrays, score: Descending

享受吧!

【讨论】:

【参考方案4】:

这里也一样,奇怪的是为什么不能。下面是另一个示例。无法得到结果。希望 firebase 可以回复并更新文档。

dbFireStore.collection('room').where('user_id.'+global.obj_user.user_id,'==',true).orderBy('last_update').get().then((qs)=>
  console.log(qs);
);

使用其他解决方法是 javascript array 和 array.sort()

【讨论】:

【参考方案5】:

我昨天在 android 上遇到了同样的问题。回调只是没有被调用。今天突然收到一条错误信息。 FAILED_PRECONDITION: The query requires an index. 它甚至在错误消息中包含一个 URL,以便一键生成该索引。

看来如果你想在你的数据上使用orderBy,你需要为那个字段创建一个索引。索引还需要按正确的顺序(DESC、ASC)。

【讨论】:

简单索引不是自动创建的吗?如何仅在一个字段上创建索引?还是条件 FIELD + Orderby FIELD 作为索引? @Pavan 据我所知,只要引入了orderBy,它就需要一个索引。对于where,我相当确定不需要索引。 @GillesBraun 正确。来自文档:Cloud Firestore requires an index for every query, to ensure the best performance. All document fields are automatically indexed, so queries that only use equality clauses don't need additional indexes. 【参考方案6】:

根据firestore document,

如果您尝试使用未映射到现有索引的范围子句进行复合查询,则会收到错误消息。错误消息包含在 Firebase 控制台中创建缺失索引的直接链接。

所以只需点击你在 Logcat 中获得的链接,它将被重定向到创建索引页面,只需创建索引。这需要一些时间。启用复合索引后,您将获得请求的查询结果。

【讨论】:

这样就解决了原题的问题。但在您查询更改的字段(例如 userId.&lt;an_actual_id_that_is_different_for_every_user&gt;)的情况下,您需要为每个用户创建一个复合索引,这是不可扩展的,因为目前 Firestore 只允许数百个这样的复合索引。

以上是关于如何在 Firebase 云 Firestore 中查询一个字段然后按另一个字段排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Firebase 云 Firestore 中查询一个字段然后按另一个字段排序?

如何使用用于 JS 开发的 firebase Emulator 设置 firebase firestore 和云功能测试套件

导出 Firestore 备份数据的云功能。使用 firebase-admin 或 @google-cloud/firestore?

Firebase 云功能 / Firestore

Firebase 云功能与 Firestore 返回“已超过截止日期”

Firebase云Firebase。如何在本地模式下在项目间移动数据