Swift+Firestore:仅保留ownerId的Tweet模型如何拉取关联用户最新数据
实现方案
你可以通过「拉取推文后批量关联查询用户数据」的方式实现,具体流程和代码如下:
1. 定义UI层展示模型
你可以新增一个组合模型,用来给UI层提供完整的推文+发布者信息,不需要修改原有的Tweet数据模型:
struct TweetWithUser: Identifiable, Hashable { let tweet: Tweet let owner: UserProfile // 直接复用推文的id作为唯一标识 var id: UUID { tweet.id } }
2. 完整数据拉取流程代码
以下是基于Firestore + Swift async/await语法的实现示例:
import FirebaseFirestore import SwiftUI class TweetViewModel: ObservableObject { /// 供UI层直接使用的带用户信息的推文数组 @Published var tweetsWithUser: [TweetWithUser] = [] private let db = Firestore.firestore() func fetchAllTweets() async throws { // 第一步:拉取全量推文数据 let tweetSnapshot = try await db.collection("tweets").getDocuments() let tweets = try tweetSnapshot.documents.compactMap { doc in try doc.data(as: Tweet.self) } // 第二步:提取所有不重复的发布者ID,避免重复请求同一用户数据 let ownerIds = Array(Set(tweets.map { $0.ownerId })) guard !ownerIds.isEmpty else { await MainActor.run { tweetsWithUser = [] } return } // 第三步:批量查询所有关联的用户数据 var userMapping: [String: UserProfile] = [:] // 用任务组并发拉取提升效率 try await withThrowingTaskGroup(of: (String, UserProfile?).self) { group in for uid in ownerIds { group.addTask { let userDoc = try await self.db.collection("users").document(uid).getDocument() let user = try? userDoc.data(as: UserProfile.self) return (uid, user) } } // 把查询到的用户数据存入字典,方便快速匹配 for try await (uid, user) in group { if let user = user { userMapping[uid] = user } } } // 第四步:组装推文和对应用户数据 let result = tweets.compactMap { tweet -> TweetWithUser? in guard let owner = userMapping[tweet.ownerId] else { return nil } return TweetWithUser(tweet: tweet, owner: owner) } // 主线程更新UI await MainActor.run { self.tweetsWithUser = result } } }
3. 可选优化方案
- 单次查询的用户ID超过10个时,可以用
whereField(FieldPath.documentID(), in: idArray)的方式分批批量拉取,比单文档请求效率更高。 - 可以增加本地用户缓存,已经拉取过的用户数据不用重复查询,减少数据库请求量。
- 如果读请求量远大于用户修改个人信息的写请求量,也可以保留原有的推文内嵌owner字段的方案,搭配Firebase Cloud Function,在用户修改个人信息时触发云函数批量更新所有该用户发布的推文中的owner字段,读性能比关联查询更高。
内容的提问来源于stack exchange,提问作者Hatim
相关产品推荐
相关产品推荐

