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

Flutter使用FirebaseFirestore查询嵌套集合返回空列表无报错问题

问题原因
    1. 前置校验缺失,查询路径可能无效
      你没有校验currentUser是否完成初始化、传入的workoutId是否合法,若currentUser!.uid或workoutId和Firestore中实际存储的路径不匹配,查询会直接返回空快照,不会抛出你捕获的常规Exception。
    1. 安全规则拦截无报错
      如果Firestore安全规则拒绝了当前用户对users/[uid]/workouts/[workoutId]/exercises路径的读权限,get()方法会返回空快照,默认不会抛出可见错误。
    1. 异步时序错误
      你对sets子集合的查询是异步操作,代码未等待sets数据返回就提前执行了setState渲染,此时listOfExerciseSets还未赋值,会出现空数据问题。
    1. 文档ID获取语法错误
      listOfExercises[i]本身就是QueryDocumentSnapshot类型,直接取.id即可获取文档ID,你写的.doc.id属于语法错误,会导致后续sets子集合的查询路径完全错误,且异步错误未被捕获所以看不到提示。
解决步骤

1. 先做问题排查

  • 打印currentUser?.uid和传入的workoutId,和Firestore控制台中实际存储的路径对比,确认路径完全一致。
  • 到Firebase控制台的安全规则沙盒中,模拟当前用户对对应路径的读请求,确认规则未拦截查询。

2. 修正代码

修正后的完整代码如下:

_getDataRowsForCompletedExerciseSets(String workoutId) async {
  // 前置校验,避免无效请求
  if (currentUser == null || workoutId.trim().isEmpty) return;
  try {
    // 清空历史数据,避免重复累加
    listOfExerciseSets.clear();
    completedExerciseSetRows.clear();

    // 获取exercise列表,去掉冗余的then调用
    final exerciseSnapshot = await FirebaseFirestore.instance
        .collection('users')
        .doc(currentUser!.uid)
        .collection("workouts")
        .doc(workoutId)
        .collection("exercises")
        .get();
    
    final listOfExercises = exerciseSnapshot.docs;
    // 打印查询结果,排查路径问题
    print("查询到的exercise数量:${listOfExercises.length}");
    if (listOfExercises.isEmpty) return;

    // 批量查询所有exercise对应的sets子集合,等待所有请求完成
    final setQueryFutures = listOfExercises.map((exerciseDoc) {
      return FirebaseFirestore.instance
          .collection('users')
          .doc(currentUser!.uid)
          .collection("workouts")
          .doc(workoutId)
          .collection("exercises")
          .doc(exerciseDoc.id) // 修正文档ID获取语法
          .collection("sets")
          .get()
          .then((setSnapshot) => _createListOfExerciseSets(setSnapshot));
    });
    await Future.wait(setQueryFutures);

    // 所有数据加载完成后再更新UI
    setState(() {
      int setCount = 1;
      for (ExerciseSet set in listOfExerciseSets) {
        completedExerciseSetRows.add(DataRow(cells: [
          DataCell(Text(setCount.toString())),
          DataCell(Text(set.weight.toString())),
          DataCell(Text(set.reps.toString())),
          DataCell(set.isSetToFailure ? const Icon(Icons.check) : const SizedBox.shrink()),
        ]));
        setCount++;
      }
    });
  } catch (e) {
    // 捕获所有类型的错误,避免漏看报错
    if (mounted) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(e.toString()),
          duration: const Duration(milliseconds: 1000),
        ),
      );
    }
  }
}
_createListOfExerciseSets(QuerySnapshot snapshot) {
  for (var doc in snapshot.docs) {
    listOfExerciseSets.add(ExerciseSet.fromFireStore(doc));
  }
  print('已加载的sets数量:${listOfExerciseSets.length}');
}

如果你需要监听sets数据的实时变化,把get()替换为snapshots().listen(_createListOfExerciseSets)即可,同时把setState逻辑移到_createListOfExerciseSets方法末尾,每次拿到新数据自动更新UI。

内容的提问来源于stack exchange,提问作者who-aditya-nawandar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 00:45:03