You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何从Firestore读取多个自定义对象?

解决Swift Firestore读取多个自定义对象的解码错误

你猜的完全没错!单文档查询返回的DocumentSnapshot和多文档查询结果里的QueryDocumentSnapshot确实是不同类型,这就是你遇到Value of type 'QueryDocumentSnapshot' has no member 'flatMap'错误的核心原因。

为什么会有这个差异?

  • 单文档查询(getDocument)返回的DocumentSnapshot是可选的——目标文档可能不存在(比如被删除了),所以需要用flatMap处理“文档不存在”的可选情况。
  • 多文档查询返回的QueryDocumentSnapshot则代表肯定存在的文档——能出现在查询结果里的都是Firestore中实际存在的文档,因此它没有flatMap方法,也不需要处理“文档不存在”的场景。

修正后的代码示例

基础循环解码版本

直接遍历查询结果中的每个QueryDocumentSnapshot,调用data(as:)方法解码即可:

db.collection("cities").whereField("capital", isEqualTo: true)
    .getDocuments() { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
            return
        }
        
        guard let snapshotDocuments = querySnapshot?.documents else {
            print("No documents found matching the query")
            return
        }
        
        for document in snapshotDocuments {
            do {
                // QueryDocumentSnapshot的data(as:)直接返回非可选的City(因为文档肯定存在)
                let city = try document.data(as: City.self)
                print("Decoded city: \(city)")
            } catch {
                // 处理单个文档解码失败的情况
                print("Failed to decode city with ID \(document.documentID): \(error)")
            }
        }
    }

批量转数组版本(更实用)

如果需要把所有解码成功的对象整理成数组,可以用compactMap批量处理,同时忽略解码失败的项:

db.collection("cities").whereField("capital", isEqualTo: true)
    .getDocuments() { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
            return
        }
        
        guard let snapshotDocuments = querySnapshot?.documents else {
            print("No documents found matching the query")
            return
        }
        
        // 批量解码为City数组,自动过滤解码失败的文档
        let capitalCities: [City] = snapshotDocuments.compactMap { document in
            do {
                return try document.data(as: City.self)
            } catch {
                print("Skipping invalid city document \(document.documentID): \(error)")
                return nil
            }
        }
        
        print("Successfully loaded \(capitalCities.count) capital cities:")
        capitalCities.forEach { city in
            print("- \(city.name) (Country: \(city.country))")
        }
    }

关键注意点

  • QueryDocumentSnapshot的data(as:)方法会直接抛出错误(比如解码失败),但不会返回可选值,因为文档本身一定存在。
  • 如果你的City模型需要自定义解码逻辑,确保它遵循FirestoreDecodable(或Codable并正确配置Firestore编码/解码规则)。

内容的提问来源于stack exchange,提问作者Stormwaker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 11:32:46