Firebase Realtime Database区间查询解码错误修复咨询
解决Firebase Realtime Database区间查询返回null导致JSON解码失败的问题
问题原因
当你使用queryStarting(atValue:)指定非起始节点的数值时,Firebase Realtime Database会返回带null占位的数组——因为数据库节点本质是有序键值对,按子字段排序后从非第一个匹配项查询时,中间缺失的索引位置会用null填充,而JSONDecoder无法将null解码为MathLevel类型,直接抛出valueNotFound错误。从你提供的快照可以看到,结果里确实包含<null>元素,这就是解码失败的直接诱因。
解决方案
提供两种可行方案,推荐第二种更贴合Firebase数据结构的实现:
方案1:过滤快照中的null值后解码
在序列化JSON前,先剔除数组中的null元素,只保留有效字典数据:
ref.child(.mathLevels) .queryOrdered(byChild: "levelCount") .queryStarting(atValue: 3) .queryEnding(atValue: 5) .observe(.value) { snapshot in do { guard let arrayValue = snapshot.value as? [[String: Any]?] else { throw NSError(domain: "DataError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效的数据格式"]) } // 过滤null,仅保留非空的字典对象 let filteredValues = arrayValue.compactMap { $0 } let jsonData = try JSONSerialization.data(withJSONObject: filteredValues) let response = try JSONDecoder().decode([MathLevel].self, from: jsonData) subject.send(response) } catch { print("fooo: \(snapshot.value)") subject.send(completion: .failure(error)) } }
方案2:将结果视为字典处理(更推荐)
Firebase Realtime Database的节点本质是字符串键对应数据对象的字典,数组只是Firebase的表现形式。直接按字典解析可彻底避免null占位问题:
ref.child(.mathLevels) .queryOrdered(byChild: "levelCount") .queryStarting(atValue: 3) .queryEnding(atValue: 5) .observe(.value) { snapshot in do { guard let dictValue = snapshot.value as? [String: [String: Any]] else { throw NSError(domain: "DataError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效的数据格式"]) } // 提取字典的值组成数组,直接解码 let valuesArray = Array(dictValue.values) let jsonData = try JSONSerialization.data(withJSONObject: valuesArray) let response = try JSONDecoder().decode([MathLevel].self, from: jsonData) subject.send(response) } catch { print("fooo: \(snapshot.value)") subject.send(completion: .failure(error)) } }
额外说明
- 用
queryStarting(atValue: 1)能正常运行,是因为查询从第一个匹配项开始,数组中没有null占位,解码流程不受影响。 - 方案2更符合Firebase的存储逻辑,数据库节点都以唯一键(如自动生成的
-Nxxxxxx)作为标识,避免了数组索引带来的无效null问题。
内容的提问来源于stack exchange,提问作者Ufuk Köşker
相关产品推荐
相关产品推荐

