Firestore查询:获取不包含指定UID的数组字段文档
解决Firestore查询数组不包含指定值的问题
问题分析
你当前使用isNotEqualTo的方式无效,核心原因是:当字段为数组类型时,isNotEqualTo会比较整个数组是否等于指定的单个字符串,而非判断数组中是否包含该字符串。包含目标UID的数组显然不等于单个UID字符串,因此这些已被跳过的资料会被错误地纳入查询结果,完全达不到过滤目的。
Firestore目前没有原生的arrayDoesNotContain查询方法,以下是两种可行的解决方案:
方案1:新增布尔标识字段(推荐)
给DiscoveryProfiles集合的每个文档添加一个布尔字段(比如skippedByCurrentUser):
- 用户跳过某份资料时,将该文档的
skippedByCurrentUser设为true - 新创建的文档默认设为
false
这种方式查询效率最高,适合 Tinder 这类需要快速加载的场景,修改后的代码如下:
func fetchInitialCards(document: QueryDocumentSnapshot?, completion: @escaping PaginatedCompletionHandler) { let targetQuery = db.collection(FIRCollections.DiscoveryProfiles.rawValue) .whereField("skippedByCurrentUser", isEqualTo: false) .limit(to: 1) let query = document == nil ? targetQuery : targetQuery.start(afterDocument: document!) query.getDocuments { snapshot, error in guard let snapshot = snapshot else { completion([], error) return } completion(snapshot.documents, error) } }
方案2:分页查询+客户端过滤(无需修改数据结构)
如果不想调整现有数据结构,可以每次批量查询多条文档(比如5条),在客户端过滤掉包含目标UID的结果,找到第一个符合要求的文档后返回,同时处理分页逻辑:
func fetchInitialCards(document: QueryDocumentSnapshot?, completion: @escaping PaginatedCompletionHandler) { let targetUID = "WoLU87LALUZOcMTu0wszo8jeBQF3" let batchSize = 5 // 每次查询的批量数 let baseQuery = db.collection(FIRCollections.DiscoveryProfiles.rawValue).limit(to: batchSize) let query = document == nil ? baseQuery : baseQuery.start(afterDocument: document!) query.getDocuments { [weak self] snapshot, error in guard let self = self, let snapshot = snapshot, error == nil else { completion([], error) return } // 过滤掉bookmarks包含目标UID的文档 let validDocs = snapshot.documents.filter { doc in guard let bookmarks = doc["bookmarks"] as? [String] else { return true // 无bookmarks字段视为有效 } return !bookmarks.contains(targetUID) } if let firstValid = validDocs.first { // 返回第一个有效文档 completion([firstValid], nil) } else { // 当前批次全无效,递归查询下一页 if let lastDoc = snapshot.documents.last { self.fetchInitialCards(document: lastDoc, completion: completion) } else { // 无更多文档 completion([], nil) } } } }
补充说明:isNotEqualTo的误区
数组类型字段的isNotEqualTo比较的是整个数组对象与指定值是否相等,而非数组元素是否包含该值。例如,["WoLU87..."]这个数组不等于字符串"WoLU87...",所以会被isNotEqualTo条件匹配,完全无法过滤掉已跳过的资料。
内容的提问来源于stack exchange,提问作者robowarrior
相关产品推荐
相关产品推荐

