Flutter中如何通过文档ID判断Firestore文档是否存在?
问题
我的Firestore中有一个名为likes的集合,该集合以用户邮箱作为文档ID存储用户相关数据,每个用户文档下嵌套liked集合,用于存储该用户点赞过的帖子ID对应的文档。
为实现点赞状态UI展示,我编写了如下StreamBuilder代码:
StreamBuilder( stream: FirebaseFirestore.instance .collection("likes") .doc(FirebaseAuth .instance.currentUser!.email) .collection("liked") .doc(id) .snapshots(), builder: (context, snapshot) { bool liked = false; if (snapshot.hasData) { var col = FirebaseFirestore.instance .collection("likes"); var doc = col.doc(FirebaseAuth .instance.currentUser!.email); var col2 = doc.collection("liked"); var doc2 = col2.doc(id).get(); if (doc2 == null) { liked = false; } else { liked = true; } } return Row( children: [ // Text(snapshot.data.toString()), IconButton( onPressed: () { liked ? FirebaseFirestore.instance .collection("likes") .doc(FirebaseAuth.instance .currentUser!.email) .delete() : FirebaseFirestore.instance .collection("likes") .doc(FirebaseAuth.instance .currentUser!.email) .collection("liked") .add({"like": true}); }, icon: GradientIcon( height: height, width: width, icon: liked ? CupertinoIcons.heart_fill : CupertinoIcons.heart, gradient: const LinearGradient( begin: Alignment.bottomLeft, end: Alignment.topRight, colors: [ Colors.deepPurple, Colors.deepPurpleAccent ]), )), ], ); }),
原本想通过上述代码判断用户是否点赞特定帖子并更新UI,但因exist关键字已废弃,且快照始终存在数据,导致判断结果始终为true。请问如何通过文档ID正确判断Firestore文档是否存在?
解决方法
原代码核心问题
- 重复发起异步查询:在
StreamBuilder的builder回调里又调用col2.doc(id).get(),这是异步操作无法同步判断结果,且完全没必要——StreamBuilder已经拿到了目标文档的快照。 - 文档存在性判断错误:应该用快照的
exists属性判断,而非判断对象是否为null; - 点赞/取消点赞逻辑错误:取消点赞时不应删除整个用户
likes文档,而是删除liked集合下对应帖子ID的文档;点赞时需用帖子ID作为文档ID创建,而非add生成随机ID,否则无法通过文档ID精准匹配。
修正后的代码
StreamBuilder<DocumentSnapshot>( stream: FirebaseFirestore.instance .collection("likes") .doc(FirebaseAuth.instance.currentUser!.email) .collection("liked") .doc(id) // 用帖子ID作为文档ID,确保精准匹配 .snapshots(), builder: (context, snapshot) { // 直接通过快照的exists属性判断文档是否存在 bool liked = snapshot.hasData && snapshot.data!.exists; return Row( children: [ IconButton( onPressed: () async { final targetDocRef = FirebaseFirestore.instance .collection("likes") .doc(FirebaseAuth.instance.currentUser!.email) .collection("liked") .doc(id); if (liked) { // 取消点赞:删除对应帖子ID的文档 await targetDocRef.delete(); } else { // 点赞:创建以帖子ID为ID的文档,内容仅需标记存在即可 await targetDocRef.set({"like": true}); } }, icon: GradientIcon( height: height, width: width, icon: liked ? CupertinoIcons.heart_fill : CupertinoIcons.heart, gradient: const LinearGradient( begin: Alignment.bottomLeft, end: Alignment.topRight, colors: [Colors.deepPurple, Colors.deepPurpleAccent], ), ), ), ], ); }, )
关键说明
- 文档存在性判断:使用
DocumentSnapshot的exists属性,这是Firestore官方推荐的判断文档是否存在的方式,不存在废弃问题; - 文档ID设计:点赞时必须用帖子ID作为文档ID(
doc(id).set(...)),而非add生成随机ID,这样后续才能通过同一个doc(id)精准查询点赞状态; - 操作逻辑修正:取消点赞仅删除
liked集合下对应帖子的文档,保留用户的likes根文档和其他点赞记录; - 自动UI更新:
StreamBuilder会自动监听文档变化,点赞/取消点赞操作完成后,快照会实时更新,UI同步切换状态。
内容的提问来源于stack exchange,提问作者Mohammed Bekele
相关产品推荐
相关产品推荐

