获取嵌套数组 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。文章还解释了如何使用CodingKeys
customize 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的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Swift 上的 Firebase 中获取嵌套键中的值