Flutter获取Firebase三级子集合drugsTime文档时类型转换错误的解决
解决Firestore获取子子集合数据的类型转换错误
问题背景
我的Firestore集合结构如下:
User--> drugs--> drugsTime
我想获取特定药物对应的子子集合drugsTime中的所有文档,但不知道该药物的文档ID,于是写了这段代码:
getData() async { final User? user = FirebaseAuth.instance.currentUser; final _uid = user?.uid; var drugID = ""; final QuerySnapshot<Map<String, dynamic>> querySnapshot = await FirebaseFirestore.instance .collection("users") .doc(_uid) .collection('drug') .where("drugName", isEqualTo: widget.title) .get(); querySnapshot.docs.forEach((element) async { drugID = element.id; }); final QuerySnapshot<Map<String, dynamic>> querySnapshot2 = (await FirebaseFirestore.instance .collection("users") .doc(_uid) .collection("drug") .doc(drugID) .get()) as QuerySnapshot<Map<String, dynamic>>; querySnapshot2.docs.forEach((element) async { drugTime .add (element.get('time')); isTaken.add(element.get("isTaken")); }); print(drugTime); print(isTaken); }
运行时抛出错误:
E/flutter (24517): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type '_JsonDocumentSnapshot' is not a subtype of type 'QuerySnapshot<Map<String, dynamic>>' in type cast E/flutter (24517): #0 _historyState.getData (package:taafi_application_v1/pages/history.dart:38:17) E/flutter (24517): <asynchronous suspension>
错误原因
- 路径错误与类型不匹配:原代码中调用
.doc(drugID).get()获取的是单个药物文档的DocumentSnapshot,但你试图把它强制转换成QuerySnapshot,这是类型不兼容的。而且你的目标是获取该药物下的drugsTime子集合,正确的路径应该在.doc(drugID)后继续调用.collection("drugsTime")再执行.get()。 - 异步forEach的问题:
querySnapshot.docs.forEach((element) async {})里的异步回调不会等待执行完成,可能导致drugID还没赋值就执行后续代码。
修正后的代码
getData() async { final User? user = FirebaseAuth.instance.currentUser; final _uid = user?.uid; if (_uid == null) { print("用户未登录"); return; } // 查询匹配drugName的药物文档 final QuerySnapshot<Map<String, dynamic>> querySnapshot = await FirebaseFirestore.instance .collection("users") .doc(_uid) .collection('drug') .where("drugName", isEqualTo: widget.title) .get(); if (querySnapshot.docs.isEmpty) { print("未找到对应药物"); return; } // 取第一个匹配的药物ID(如果多个匹配可根据需求调整) final drugID = querySnapshot.docs.first.id; // 获取该药物下的drugsTime子集合数据 final QuerySnapshot<Map<String, dynamic>> timeSnapshot = await FirebaseFirestore.instance .collection("users") .doc(_uid) .collection("drug") .doc(drugID) .collection("drugsTime") // 正确指向子子集合 .get(); // 遍历子集合文档,填充数据 drugTime.clear(); // 先清空避免重复数据 isTaken.clear(); for (final doc in timeSnapshot.docs) { drugTime.add(doc.get('time')); isTaken.add(doc.get("isTaken")); } print(drugTime); print(isTaken); }
关键修改点说明
- 修正集合路径:明确指向
drugsTime子集合,确保获取的是子集合的QuerySnapshot,无需类型转换。 - 处理异步逻辑:直接取查询结果的第一个文档ID,避免异步forEach导致的赋值延迟;用普通for循环遍历子集合文档,保证数据正确填充。
- 增加空值判断:添加用户未登录、未找到药物的判断,避免空指针异常。
内容的提问来源于stack exchange,提问作者Sara Almashharawi
相关产品推荐
相关产品推荐

