Firebase中如何查询含用户ID的post-saves所属帖子文档
问题分析
你当前的FetchUserSavedPosts方法存在两个核心问题:
- 错误地直接查询
post-saves子集合中的用户ID文档,这些文档仅存储用户ID信息,无法解析为完整的Post对象; - Firestore不支持通过子集合的条件直接反向查询父集合文档,必须先定位到包含目标用户ID的
post-saves所属的帖子ID,再批量获取对应帖子数据。
修正方案
方案一:适配现有数据结构的查询方式
先遍历所有帖子,筛选出包含当前用户ID的post-saves对应的帖子ID,再批量获取完整帖子数据:
static func fetchUserSavedPosts(uid: String) async throws -> [Post] { // 1. 获取所有帖子的基础信息 let postsSnapshot = try await postsCollection.getDocuments() var savedPostIDs: [String] = [] // 2. 逐个检查帖子的post-saves集合是否包含当前用户 for postDoc in postsSnapshot.documents { let saveDoc = try await postDoc.reference.collection("post-saves").document(uid).getDocument() if saveDoc.exists { savedPostIDs.append(postDoc.documentID) } } // 3. 批量获取收藏的完整帖子数据 if savedPostIDs.isEmpty { return [] } let targetPostsSnapshot = try await postsCollection.whereField("id", in: savedPostIDs).getDocuments() return try targetPostsSnapshot.documents.compactMap { try $0.data(as: Post.self) } }
注意:如果帖子数量较大,这种遍历方式会消耗大量读取次数,建议使用下面的优化方案。
方案二:优化数据结构(推荐)
在每个用户的文档下新增saved-posts子集合,用户收藏帖子时同时在两处记录(帖子的post-saves+用户的saved-posts),后续查询效率会大幅提升:
1. 修改收藏帖子的逻辑
static func savePost(_ post: Post) async throws { guard let uid = Auth.auth().currentUser?.uid else { return } // 定义两个需要更新的文档引用 let postSaveRef = postsCollection.document(post.id).collection("post-saves").document(uid) let userSaveRef = Firestore.firestore().collection("users").document(uid).collection("saved-posts").document(post.id) let userIDData = UserID(id: uid) guard let encodedData = try? Firestore.Encoder().encode(userIDData) else { return } // 事务批量写入,保证操作原子性 try await Firestore.firestore().runTransaction { transaction in transaction.setData(encodedData, forDocument: postSaveRef) transaction.setData(["postID": post.id], forDocument: userSaveRef) } }
2. 高效查询用户收藏的帖子
static func fetchUserSavedPosts(uid: String) async throws -> [Post] { // 1. 从用户的saved-posts集合获取所有收藏的帖子ID let userSavedSnapshot = try await Firestore.firestore().collection("users").document(uid).collection("saved-posts").getDocuments() let savedPostIDs = userSavedSnapshot.documents.map { $0.documentID } // 2. 批量查询完整帖子数据 if savedPostIDs.isEmpty { return [] } let postsSnapshot = try await postsCollection.whereField("id", in: savedPostIDs).getDocuments() return try postsSnapshot.documents.compactMap { try $0.data(as: Post.self) } }
原代码其他问题修正
FetchUserSavedPosts中的postsCollection.document()是创建空文档引用,属于无效操作,已在修正方案中移除;savepost方法中的async let _ = try await postRef.setData(encodedPost)无需使用async let,直接调用try await postRef.setData(encodedPost)即可。
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

