Swift Firestore中如何通过文档引用获取关联的BookStyle数据?
问题描述
我定义了如下Book模型:
struct Book: Identifiable { var id = UUID().uuidString var text: String var styleReference: DocumentReference var style: BookStyle // 不在Firestore文档中存储 }
以及BookStyle模型:
struct BookStyle: Identifiable { var id = UUID().uuidString var imageUrlString: String var fontString: String }
我的Firestore中Book文档结构包含text字段和styleReference引用字段。当前通过以下方法获取Books数据:
func fetchData() { db.collection("books").addSnapshotListener { (querySnapshot, error) in guard let documents = querySnapshot?.documents else { return } self.books = documents.compactMap { queryDocumentSnapshot -> Book? in return try? queryDocumentSnapshot.data(as: Book.self) } } }
我已经持有styleReference文档引用,但不清楚应该在何处获取并关联对应的BookStyle数据。
解决方案
你可以在解析Book之后,针对每个styleReference发起查询获取BookStyle,以下是几种实用的实现方式:
方式一:异步逐个填充Style(推荐基础场景)
func fetchData() { db.collection("books").addSnapshotListener { (querySnapshot, error) in guard let documents = querySnapshot?.documents else { return } var tempBooks: [Book] = [] for doc in documents { guard var book = try? doc.data(as: Book.self) else { continue } // 异步查询对应的style文档 book.styleReference.getDocument { styleDoc, error in DispatchQueue.main.async { if let styleDoc = styleDoc, let style = try? styleDoc.data(as: BookStyle.self) { book.style = style // 更新数组中对应的Book并刷新UI if let index = tempBooks.firstIndex(where: { $0.id == book.id }) { tempBooks[index] = book self.books = tempBooks } } } } tempBooks.append(book) } self.books = tempBooks } }
方式二:批量查询优化性能(适合书籍数量较多的场景)
如果一次性加载大量书籍,逐个查询会有性能损耗,可以用批量查询接口一次性获取所有Style文档:
func fetchData() { db.collection("books").addSnapshotListener { (querySnapshot, error) in guard let documents = querySnapshot?.documents else { return } let books = documents.compactMap { try? $0.data(as: Book.self) } let styleReferences = books.map { $0.styleReference } // 批量获取所有style文档 db.getAllDocuments(styleReferences) { styleDocs, error in guard let styleDocs = styleDocs else { return } var styledBooks: [Book] = [] for book in books { var mutableBook = book // 匹配对应的style文档 if let styleDoc = styleDocs.first(where: { $0.reference == book.styleReference }), let style = try? styleDoc.data(as: BookStyle.self) { mutableBook.style = style } styledBooks.append(mutableBook) } DispatchQueue.main.async { self.books = styledBooks } } } }
方式三:实时监听Style变化(需要同步Style更新的场景)
如果需要实时感知BookStyle的修改,可以给每个styleReference添加快照监听:
func fetchData() { db.collection("books").addSnapshotListener { (querySnapshot, error) in guard let documents = querySnapshot?.documents else { return } self.books = documents.compactMap { doc -> Book? in guard var book = try? doc.data(as: Book.self) else { return nil } // 给styleReference添加监听,实时更新style book.styleReference.addSnapshotListener { styleDoc, error in DispatchQueue.main.async { if let styleDoc = styleDoc, let style = try? styleDoc.data(as: BookStyle.self) { if let index = self.books.firstIndex(where: { $0.id == book.id }) { self.books[index].style = style } } } } return book } } }
注意事项
- 所有UI更新操作必须放在主线程,用
DispatchQueue.main.async包裹 - 可以给
BookStyle设置默认值,避免查询失败导致UI异常 - 批量查询时要注意Firestore的批量操作限制(单次最多500个文档)
内容的提问来源于stack exchange,提问作者X Æ A-12
相关产品推荐
相关产品推荐

