如何复用Firestore的users集合QuerySnapshot获取内嵌posts集合?
问题
我在探索页面通过get()获取整个users集合来创建用户列表和搜索结果。每个用户文档下包含一个posts集合,我需要获取该集合来生成帖子的GridView。为节省成本,希望复用已获取的users集合QuerySnapshot,而非再次逐个请求每个posts集合,请问这是否可行?
当前代码
void fetchUsers() async { final userRef = FirebaseFirestore.instance.collection('users'); final QuerySnapshot result = await userRef.get(); final docs = result.docs.asMap(); docs.forEach((index, value) { final profile = ProfileObject.fromJson(value.data() as Map<String, dynamic>); usersList.add(UserSearchResult(profile, value.id)); /// 下面是获取帖子的代码,无法运行,需要解决方案 final QuerySnapshot postsResult = value.get('posts'); final posts = postsResult.docs.asMap(); posts.forEach((index, value) { final post = Post.fromJson(value.data() as Map<String, dynamic>); postsList.add(post); }); }); print(usersList); print(postsList); }
Firestore结构
- users
- uid(文档)
- posts(子集合)
- info(字段)
- uid(文档)
- posts(子集合)
- info(字段)
- uid(文档)
回答
这种方式不可行。原因很明确:调用userRef.get()获取users集合文档时,只会返回用户文档自身的字段数据,不会自动包含子集合posts的内容。Firestore的集合查询默认不会递归获取子集合,子集合属于独立的资源,必须单独发起请求才能获取。
你当前代码里的value.get('posts')会报错,因为用户文档中不存在名为posts的字段——posts是子集合,不是文档字段,所以get('posts')会返回null,无法转换成QuerySnapshot。
如果想优化成本和请求效率,可以参考以下几种方案:
- 嵌入帖子数据到用户文档:如果帖子数量较少,可以将帖子作为数组字段存储在用户文档中,这样获取用户文档时就能一并拿到帖子数据。但要注意Firestore单文档有1MB的大小限制,帖子数量多的话不适用这种方式。
- 批量获取子集合:使用
Future.wait()批量发起所有用户posts集合的请求,比逐个循环请求的效率更高,能减少异步等待时间。示例代码如下:
void fetchUsersAndPosts() async { final userRef = FirebaseFirestore.instance.collection('users'); final QuerySnapshot userSnapshot = await userRef.get(); // 批量创建所有posts集合的请求Future final List<Future<QuerySnapshot>> postsFutures = userSnapshot.docs.map((userDoc) { return userDoc.reference.collection('posts').get(); }).toList(); // 等待所有请求完成 final List<QuerySnapshot> postsSnapshots = await Future.wait(postsFutures); // 处理用户数据和对应帖子数据 for (int i = 0; i < userSnapshot.docs.length; i++) { final userDoc = userSnapshot.docs[i]; final profile = ProfileObject.fromJson(userDoc.data() as Map<String, dynamic>); usersList.add(UserSearchResult(profile, userDoc.id)); final postsSnapshot = postsSnapshots[i]; postsSnapshot.docs.forEach((postDoc) { final post = Post.fromJson(postDoc.data() as Map<String, dynamic>); postsList.add(post); }); } print(usersList); print(postsList); }
- 按需加载帖子:比如等用户点击某个用户条目时,再加载该用户的帖子,而不是一次性加载所有用户的帖子。这种方式能大幅减少请求次数和成本,尤其当用户数量较多时更实用。
内容的提问来源于stack exchange,提问作者Globe
相关产品推荐
相关产品推荐

