You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

错误原因

  1. 路径错误与类型不匹配:原代码中调用.doc(drugID).get()获取的是单个药物文档的DocumentSnapshot,但你试图把它强制转换成QuerySnapshot,这是类型不兼容的。而且你的目标是获取该药物下的drugsTime子集合,正确的路径应该在.doc(drugID)后继续调用.collection("drugsTime")再执行.get()。
  2. 异步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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 15:40:37