iOS - Firestore 复合索引中的索引上的多个 orderBy 和 where 子句
Posted
技术标签:
【中文标题】iOS - Firestore 复合索引中的索引上的多个 orderBy 和 where 子句【英文标题】:iOS - Firestore multiple orderBy and where clauses on indexes within a composite index 【发布时间】:2019-02-02 23:10:25 【问题描述】:我正在尝试使用 Firestore 做三件事:
获取“contentType”字段为“basic”的文档, 获取在某个时间点之后创建的文档。 (示例中为凌晨 5 点。) 根据“喜欢”计数对文档进行排序。contents
集合中的文档如下所示(省略不必要的细节):
date: Timestamp;
contentType: string;
response:
like: Number;
;
这是 ios 代码:
let dateKey = "date"
let likeKey = "response.like"
let startDate = Date().setLocalHour(5)
let timestamp = Timestamp(date: startDate)
Firestore.firestore()
.collection(path: .contents)
.whereField(.contentType, isEqualTo: "basic")
.whereField(dateKey, isGreaterThanOrEqualTo: timestamp)
.order(by: dateKey, descending: true)
.order(by: likeKey, descending: true)
.limit(to: Constant.fetchLimit)
order(by: dateKey)
部分是必需的,因为 Firebase 需要它。否则会抛出异常,抱怨 where 子句和 orderby 子句不匹配。
我已经创建了一个显示contents
contentType Ascending date Descending response.like Descending
的复合索引。
预期与结果
我希望文档按like
计数排序,并且所有文档都是“基本”类型并在今天凌晨 5 点之后创建。
相反,只应用前两个条件,而完全忽略第三个条件。两种条件的不同组合起作用。是这三个条件结合起来是行不通的。
所以我的问题是,由于 Firebase 文档没有说明有两个以上的多个 orderby 和 where 组合,这是一个错误还是不可能的事情?
【问题讨论】:
Firestore 查询只能执行范围查询或一键排序。在您的情况下,这意味着您必须要么 按dateKey
排序/过滤或 获得按order
排序的结果,但您可以同时拥有两者。这已记录在 here 中,在 this video 和 this question 中进行了介绍。
很抱歉,但我阅读了文档,问题中只有一个范围过滤器,尽管有两种。文档说一个范围过滤器,而不是排序。
where 子句有两个,但第一个是相等,而不是范围。我已经看到了你链接的问题,但它完全不同。
@FrankvanPuffelen 请检查我的 cmets。这不是重复的。
您订购的是两个键 (.order(by: dateKey, descending: true).order(by: likeKey, descending: true)
),由于 Todd 在我链接的视频中解释的原因,这 (afaik) 是不可能的。
【参考方案1】:
我找到了解决问题的方法。
原始查询需要三个字段的复合索引。所以date
上只有一个范围比较--contentType
仅用于相等性检查--date
和response.like
上的两个排序,两者都构成复合索引.
相反,我决定在contents
文档中添加一个字段,如下所示:
tags: string[]; // the new field.
date: Timestamp;
contentType: string;
response:
like: Number;
;
新查询如下所示:
Firestore.firestore()
.collection(path: .contents)
.whereField(.tags, arrayContains: Date.getDatabaseKey())
.whereField(.contentType, isEqualTo: "basic")
.order(by: likeKey, descending: true)
.limit(to: Constant.fetchLimit)
(Date.getDatabaseKey()
只是根据当前日期创建一个yyyy-MM-dd
字符串。)
此查询需要两个复合索引:
tags Arrays response.like Descending
和 contentType Ascending response.like Descending
。
幸运的是,这就像一个魅力。
添加信息 原始查询检查了某一天凌晨 5 点之后创建的文档的集合,对我来说,范围检查似乎是问题所在。
只要上面的Date.getDatabaseKey()
方法在5:00:00 到次日4:59:59 小时内生成同一天的键,这个新查询基本上具有效果一样。
【讨论】:
@FrankvanPuffelen 很高兴能跟进这个问题,无论原始查询确实是不支持的东西还是失败是一个错误。如果不支持,最好在文档中提供更多信息。 这是否满足最初的问题? contentType = 'basic' 并且在凌晨 5 点之后创建 然后按赞排序?我没有看到任何会在凌晨 5 点之后提取范围数据的东西。我可能在新结构或查询中忽略了它。 @Jay 只要Date.getDatabaseKey()
生成相应的字符串键,它就应该可以工作。例如,直到凌晨 4:59:59,生成前一天的密钥,从凌晨 5:00:00 开始,生成具有相同日期的密钥。这应该与检查 5 AM 之后的时间戳具有相同的效果。其余的都是一样的。
我可能应该将它添加到答案中。谢谢。以上是关于iOS - Firestore 复合索引中的索引上的多个 orderBy 和 where 子句的主要内容,如果未能解决你的问题,请参考以下文章
Pandas中xs()函数索引复合索引数据的不同切面数据(索引复合索引中需要的数据):索引列复合索引中的一个切面索引行复合索引中的一个切面
SQL Server创建复合索引时,复合索引列顺序对查询的性能影响