使用Firestore的getDocuments查询获取数据时返回空数组的问题排查求助
我来帮你捋捋Firestore查询返回空数组的几个常见坑,结合你的代码场景逐一分析:
目标文档/子集合不存在
你的查询路径是users/{username}/notifications,首先要确认几个点:- UserDefaults里存储的
username和Firestore中users集合下的文档ID是否完全一致(Firestore对大小写、特殊字符敏感,比如"John"和"john"是两个不同的文档); - 该用户文档下是否真的存在名为
notifications的子集合,有没有拼写错误(比如少写字母、大小写错误)。
- UserDefaults里存储的
Firestore安全规则限制
如果你的Firestore安全规则没有正确配置,可能会导致查询被拦截,返回空结果(甚至不报错)。比如规则没有验证用户身份,或者路径匹配逻辑错误。可以先临时将规则改为开放测试(仅限开发环境):rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if true; } } }如果测试后能拿到数据,说明问题出在安全规则上,再针对性调整规则(比如只允许用户读取自己的通知)。
IGNotification初始化失败(compactMap过滤掉所有元素)
你用了compactMap来转换文档数据,要是IGNotification(with: $0.data())这个初始化方法对某些文档返回了nil,compactMap会把这些无效元素全部过滤,最终得到空数组。
建议先单独打印每个文档的原始数据,看看是否存在字段缺失、类型不匹配的情况(比如Firestore里存的是数字,你代码里用字符串接收)。异步逻辑或UserDefaults时机问题
虽然你的代码里用guard判断了username是否存在,但要确保调用getNotifications的时候,UserDefaults里的username已经被正确设置。比如有没有可能在用户登录流程还没完成时就调用了这个函数?
调试建议
修改你的查询代码,增加更多调试日志,帮你定位问题:
public func getNotifications( completion: @escaping ([IGNotification]) -> Void ) { guard let username = UserDefaults.standard.string(forKey: "username") else { print("UserDefaults中没有找到username") completion([]) return } print("当前查询的username:\(username)") let ref = firestoreDatabase.collection("users").document(username).collection("notifications") ref.getDocuments { snapshot, error in // 先检查错误 if let error = error { print("Firestore查询错误:\(error.localizedDescription)") completion([]) return } // 检查是否拿到文档 guard let documents = snapshot?.documents else { print("未获取到任何文档") completion([]) return } print("成功获取到\(documents.count)个通知文档") // 打印第一个文档的原始数据 if let firstDoc = documents.first { print("第一个文档数据:\(firstDoc.data())") } // 分步处理映射 let notifications = documents.compactMap { doc in let notification = IGNotification(with: doc.data()) if notification == nil { print("映射失败的文档数据:\(doc.data())") } return notification } print("映射后得到\(notifications.count)个有效通知") completion(notifications) } }
通过这些日志,你能清楚看到是哪一步出了问题——是没拿到文档,还是映射失败,或者是username本身就不对。
内容的提问来源于stack exchange,提问作者Swimmer97

