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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 15:27:49