获取嵌套数组 Firebase + SwiftUI

Posted

技术标签:

【中文标题】获取嵌套数组 Firebase + SwiftUI【英文标题】:Fetch nested array Firebase + SwiftUI 【发布时间】:2021-08-09 13:29:09 【问题描述】:

我试图在 Firebase 存储中解析我的文档中的嵌套数组。 我有一个获取数据和文档结构的功能。你能帮我更新一下我的功能吗?)

【问题讨论】:

我可以建议您的源代码使用代码 sn-ps 而不是屏幕截图吗?这将使人们更容易回答您的问题,因为他们将能够重用您的代码。使用屏幕截图显示 Firebase 控制台是可以的(实际上非​​常有用)。 【参考方案1】:

请帮自己一个忙,不要手动将数据从 Firestore 映射到 Swift。

Firestore 支持 Swift Codable 协议,这让事情变得轻松了很多

使用带 Firestore 的 Codable

这是一个简短的 sn-p,展示了如何调整您的代码:

struct Order: Identifiable, Codable 
  @DocumentID var id: String
  var number: Int
  var status: String
  var clientName: String
  // ...

class OrdersViewModel: ObservableObject 
  @Published var orders = [Order]()
  @Published var errorMessage: String?
  
  private var db = Firestore.firestore()
  private var listenerRegistration: ListenerRegistration?
  
  public func unsubscribe() 
    if listenerRegistration != nil 
      listenerRegistration?.remove()
      listenerRegistration = nil
    
  
  
  func subscribe() 
    if listenerRegistration == nil 
      listenerRegistration = db.collection("orders")
        .addSnapshotListener  [weak self] (querySnapshot, error) in
          guard let documents = querySnapshot?.documents else 
            self?.errorMessage = "No documents in 'orders' collection"
            return
          
          
          self?.orders = documents.compactMap  queryDocumentSnapshot in
            let result = Result  try queryDocumentSnapshot.data(as: Order.self) 
            
            switch result 
            case .success(let order):
              if let order = order 
                // An Order value was successfully initialized from the DocumentSnapshot.
                self?.errorMessage = nil
                return order
              
              else 
                // A nil value was successfully initialized from the DocumentSnapshot,
                // or the DocumentSnapshot was nil.
                self?.errorMessage = "Document doesn't exist."
                return nil
              
            case .failure(let error):
              // An Order value could not be initialized from the DocumentSnapshot.
              switch error 
              case DecodingError.typeMismatch(_, let context):
                self?.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
              case DecodingError.valueNotFound(_, let context):
                self?.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
              case DecodingError.keyNotFound(_, let context):
                self?.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
              case DecodingError.dataCorrupted(let key):
                self?.errorMessage = "\(error.localizedDescription): \(key)"
              default:
                self?.errorMessage = "Error decoding document: \(error.localizedDescription)"
              
              return nil
            
          
        
    
  
  

虽然这可能看起来比您的代码更复杂,但关键是:

try queryDocumentSnapshot.data(as: Order.self)

其余代码执行一些错误处理(您绝对应该这样做),因此增加了一些噪音。

映射数组

使用 Codable 使映射数组变得非常简单。您可以在数组中使用 Codable 本身的任何类型。

因此,对于您的订单商品,请使用以下内容:

struct OrderItem: Codable 
  var cost: Int
  var name: String

然后更新Order结构如下:

struct Order: Identifiable, Codable 
  @DocumentID var id: String
  var number: Int
  var status: String
  var clientName: String
  var items: [OrderItem]
  // ...

就是这样 - 其他所有内容都将自动处理。详情请参阅我的文章中的Mapping arrays。

资源

更多详情请参考Mapping Firestore Data in Swift - The Comprehensive Guide和SwiftUI: Mapping Firestore Documents using Swift Codable - Application Architecture for SwiftUI & Firebase。文章还解释了如何使用CodingKeyscustomize the mapping。

【讨论】:

我使用了你文章中的材料,我遇到了一些类似的问题。 self.orders = try document.data(as: MedcineModel.self) 错误是“无法分配 'MyModel 类型的值?'输入 [MyModel] @PeterSmith【参考方案2】:

您不清楚您的问题是什么,我假设数组数据无法解析。问题很明显,不是as! [Any]。 尝试使用as! [Any:Any],因为它不是对象列表,而是字典列表。

【讨论】:

【参考方案3】:

我建议在文档中使用子集合。对我来说更容易处理查询。(例如,collection(Orders).document(orderid).collection(orderedFood).getDoc...) 但是如果你想要嵌套对象,这里有一个链接:

[https://levelup.gitconnected.com/firestore-to-swift-models-with-complex-types-enums-and-arrays-282893affb15]

【讨论】:

【参考方案4】:

你可以如何将你的结构体声明成一个变量

var dataStruct = [Struct]()

之后,您需要检查您的 fetchOrder 方法,一种解决方案类似于:

func fetchOrder() 
db.collection("orders").order(by: "items").addSnapshotListener  snapshot, error in
        if error != nil 
            return
         else 
            guard let documents = snapshot?.documents else  return 
            
            for eachDoc in documents 
                let data = eachDoc.data()
                guard let items = data["items"] as? [String] else  continue 
                let itemArray = generateMovieItemsWith(items: items)
                self.dataStruct.append(itemArray)
            
        
    

【讨论】:

以上是关于获取嵌套数组 Firebase + SwiftUI的主要内容,如果未能解决你的问题,请参考以下文章

无法将数据从 Firebase 附加到数组 SwiftUI

如何在 Swift 上的 Firebase 中获取嵌套键中的值

Firebase 引用对象不会保存到 SwiftUI 中的变量

SwiftUI - 从嵌套数组中列出对象

尝试从 SwiftUI 视图中的嵌套数组调用

SwiftUI 和 Firebase:从推送通知中获取信息