如何在Firestore中用Where条件查询指定枚举值的文档
解决Firestore中Codable枚举的查询问题
问题根源
你定义的无关联值Codable枚举,Swift默认会将其编码为仅包含当前case名称作为键、值为空的对象(比如notOpen会被编码为{"notOpen": ""}),这种嵌套存储结构导致你之前的查询方式无法正确匹配。
临时解决方案(针对已存储的数据)
如果不想修改现有数据结构,可以将目标枚举值编码为对应字典,再用该字典作为查询条件:
let targetStatus = washingPowderState.notOpen do { // 将枚举编码为Firestore存储的字典格式 let encodedData = try JSONEncoder().encode(targetStatus) guard let statusDict = try JSONSerialization.jsonObject(with: encodedData, options: []) as? [String: Any] else { print("编码枚举失败") return } db.collection(K.NoSQLCollections.washingPowder) .whereField("roles.\(uid)", isEqualTo: K.Roles.owner) .whereField("status", isEqualTo: statusDict) .getDocuments { querySnapshot, err in // 处理查询结果 } } catch { print("编码枚举出错:\(error)") }
最优解决方案(修改枚举编码逻辑)
更推荐修改枚举的Codable实现,让它直接存储为字符串,这样查询更简洁直观,也符合Firestore的常用数据格式:
方法1:使用String原始值枚举
让枚举继承String类型,Codable会自动将其编码为对应的字符串:
enum WashingPowderState: String, Codable { case notOpen, open, used }
此时Firestore中status字段的值会是"notOpen"/"open"/"used",查询代码可以简化为:
db.collection(K.NoSQLCollections.washingPowder) .whereField("roles.\(uid)", isEqualTo: K.Roles.owner) .whereField("status", isEqualTo: WashingPowderState.notOpen.rawValue) .getDocuments { querySnapshot, err in // 处理查询结果 }
方法2:自定义Codable实现
如果不想使用原始值,可以手动实现编码解码逻辑,强制将枚举转为字符串存储:
enum WashingPowderState: Codable { case notOpen, open, used func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .notOpen: try container.encode("notOpen") case .open: try container.encode("open") case .used: try container.encode("used") } } init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let rawValue = try container.decode(String.self) switch rawValue { case "notOpen": self = .notOpen case "open": self = .open case "used": self = .used default: throw DecodingError.dataCorruptedError(in: container, debugDescription: "无效的洗涤粉状态值:\(rawValue)") } } }
查询方式和方法1一致,直接匹配对应的字符串值即可。
内容的提问来源于stack exchange,提问作者Max Mikkelsen
相关产品推荐
相关产品推荐

