iOS端Firestore使用notIn过滤时按timestamp排序触发无效查询如何解决
Firestore 排除指定字段值查询的解决方案
这个报错是Firestore的内置查询限制导致的:所有使用不等式类筛选(包含notIn、notEqualTo、大小比较等)的字段,必须作为查询的第一个排序字段,否则无法匹配复合索引完成查询。
无效查询。你在字段'uid'上使用了不等式筛选(notEqual、lessThan、lessThanOrEqual、greaterThan或greaterThanOrEqual),因此你必须将'uid'作为你查询的第一个排序字段,但你当前的第一个排序字段是'timestamp'。
方案1:客户端过滤(最常用,适配按时间排序的需求)
直接去掉服务端的uid筛选逻辑,先按timestamp的规则查询数据,拿到查询结果后在本地过滤掉uid属于排除列表的条目即可。
如果排除的条目占比不高,可以适当放大查询条数,避免过滤后返回结果不足要求的3条:
db.collection("MyCollection") .order(by: "timestamp", descending: false) .whereField("timestamp", isGreaterThan: localTimestamp) .limit(to: 10) // 放大查询条数,预留过滤余量 .getDocuments { (snapshot, error) in if let err = error{ print(err.localizedDescription) return } var modelsData = [Model]() let excludeUids = [reportedUids, [currentUid]].flatMap{$0} // 合并排除列表 snapshot?.documents.forEach({ (doc) in let dict = doc.data() // 本地过滤排除指定uid的文档 guard let uid = dict["uid"] as? String, !excludeUids.contains(uid) else { return } var model = Model() model.transformModelWith(dict: dict) modelsData.append(model) }) // 取过滤后的前3条 let resultModels = Array(modelsData.prefix(3)) let lastDocumentFetched = snapshot?.documents.last DispatchQueue.main.async { completion(resultModels, lastDocumentFetched!) } } }
方案2:调整数据结构,使用等于筛选规避不等式限制
如果你需要排除的规则相对固定,可以新增一个标记字段,例如isValid,提前将需要排除的uid对应的文档的isValid字段设为false,其余设为true。
此时查询使用等于筛选,不需要调整排序顺序,也不需要客户端过滤:
db.collection("MyCollection") .order(by: "timestamp", descending: false) .whereField("timestamp", isGreaterThan: localTimestamp) .whereField("isValid", isEqualTo: true) // 等于筛选无排序优先级限制 .limit(to: 3) // 后续逻辑和原代码一致
方案3:适配Firestore查询规则调整排序逻辑
如果你能接受先按uid排序再按timestamp排序的结果顺序,可以调整排序字段顺序来符合查询要求,这种方案不需要客户端过滤,但结果排序逻辑会发生变化:
db.collection("MyCollection") .order(by: "uid", descending: false) // 不等式筛选字段放第一个排序位 .order(by: "timestamp", descending: false) .whereField("timestamp", isGreaterThan: localTimestamp) .whereField("uid", notIn: [reportedUids, currentUid]) .limit(to: 3) // 后续逻辑和原代码一致
内容的提问来源于stack exchange,提问作者StackGU
相关产品推荐
相关产品推荐

