无法从嵌套集合中检索数据

Posted

技术标签:

【中文标题】无法从嵌套集合中检索数据【英文标题】:Cannot retrieve data from nested collection 【发布时间】:2022-01-07 01:16:03 【问题描述】:
_getDataRowsForCompletedExerciseSets(workoutId) async 
try 
  List listOfExercises = await FirebaseFirestore.instance
      .collection('users')
      .doc(currentUser!.uid)
      .collection("workouts")
      .doc(workoutId)
      .collection("exercises")
      .get()
      .then((snapShot) => snapShot.docs);

  for (int i = 0; i < listOfExercises.length; i++) 
    FirebaseFirestore.instance
        .collection('users')
        .doc(currentUser!.uid)
        .collection("workouts")
        .doc(workoutId)
        .collection("exercises")
        .doc(listOfExercises[i].doc.id.toString())
        .collection("sets")
        .snapshots()
        .listen(_createListOfExerciseSets);
  

  setState(() 
    for (ExerciseSet set in listOfExerciseSets) 
      //print(set.weight);
      completedExerciseSetRows.add(DataRow(cells: [
        DataCell(Text(setCount.toString())),
        //const DataCell(VerticalDivider(thickness: 5)),
        DataCell(Text(set.weight.toString())),
        //const DataCell(VerticalDivider(thickness: 5)),
        DataCell(Text(set.reps.toString())),
        //const DataCell(VerticalDivider(thickness: 5)),
        DataCell((isSetToFailure == true) ? Icon(Icons.check) : Icon(null))
        //const DataCell(VerticalDivider(thickness: 5)),
      ]));
    
  );
 on Exception catch (_, e) 
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(
      content: Text(e.toString()),
      duration: Duration(milliseconds: 1000),
    ),
  );

return Container();

    _createListOfExerciseSets(QuerySnapshot snapshot) 
  var docs = snapshot.docs;
  for (var doc in docs) 
    listOfExerciseSets.add(ExerciseSet.fromFireStore(doc));
  
  print('EXERCISE SETS = ' + listOfExerciseSets.toString());

我有以下数据库结构:

users-->id-->workouts-->id-->exercises-->id-->sets-->id--fields

我正在尝试获取特定锻炼(id)的练习以及每个练习的集合(包括字段)。 listOfExercises 始终为空(0 项)。也没有任何错误显示。

【问题讨论】:

请也分享您的 Json 响应。 什么json响应?很抱歉没有 json 响应。 我已经为 _createListOfExerciseSets 添加了代码;虽然 listOfExercises 与 listOfExerciseSets 不同。 setState 中添加一些调试prints,你会看到它们在prints 之前在_createListOfExerciseSets 中打印 - 这就是为什么你总是有空数据的原因 _createListOfExerciseSets 是在 _getDataRowsForCompletedExerciseSets 中调用 setState 之前调用的单独方法。如何在 _createListOfExerciseSets 中的 setState 之后添加打印?! _createListOfExerciseSets 中没有 setState。 【参考方案1】:

这是我现在拥有的:

     Widget build(BuildContext context) 
    var exercisesRef = usersRef
        .doc(currentUser!.uid)
        .collection('workouts')
        .doc(workoutId)
        .collection('exercises');
    return FutureBuilder<QuerySnapshot>(
      future: exercisesRef.get(),
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) 
        switch (snapshot.connectionState) 
          case ConnectionState.active:
            return const Center(
              child: kCPI,
            );
          case ConnectionState.waiting:
            return const Center(
              child: kCPI,
            );
          case ConnectionState.none:
            return const Center(
              child: kCPI,
            );
          case ConnectionState.done:
            if (snapshot.hasError) 
              return Text('Error: $snapshot.error');
             else if (!snapshot.hasData) 
              //print('WORKOUTID = ' + workoutId);
              return const Text("Document does not exist");
             else if (snapshot.hasData &&
                snapshot.connectionState == ConnectionState.done) 
              final exercises = snapshot.data!.docs;
              List<Widget> completedExercisesWidgetsList = [];

              final _controller = ScrollController();

              // for loop - loop through all the exercises for the current workout
              for (var doc in exercises) 
                bool isRowsGeneratedForPreviousExercises = false;
                dataRowsForCompletedExercises = [];
                var setList = [];
                Map<String, dynamic> exercise;
                var exerciseName = '';
                exercise = doc.data() as Map<String, dynamic>;
                setList = exercise['sets'];
                exerciseName = exercise['name'];

                //loop through the sets for the exercise

                for (var set in setList) 
                  var setNumber = 0;
                  var weight = '';
                  var reps = '';
                  var isToFailure = false;
                  setNumber = setList.indexOf(set) + 1;
                  weight = set['weight'].toString();
                  reps = set['reps'].toString();
                  isToFailure = set['isToFailure'];
                  if (isRowsGeneratedForPreviousExercises == false) 
                    _generateDataTableRowsForCompletedExercises(
                      setNumber,
                      weight,
                      reps,
                      isToFailure,
                    );
                  
                
                isRowsGeneratedForPreviousExercises = true;
                completedExercisesWidgetsList
                    .add(_completedExercisesDataTableWidget(exerciseName));
               //for loop ends

              ///Return list of widgets - one widget for each completed exercise for the current workout
              return Column(
                mainAxisSize: MainAxisSize.max,
                children: [
                  Expanded(

                    child: ScrollConfiguration(
                      behavior: ScrollConfiguration.of(context).copyWith(
                        dragDevices: 
                          PointerDeviceKind.touch,
                          PointerDeviceKind.mouse,
                        ,
                      ),
                      child: ListView(
                        shrinkWrap: true,
                        controller: _controller,
                        physics: const AlwaysScrollableScrollPhysics(),
                        scrollDirection: Axis.vertical,
                        children: completedExercisesWidgetsList,
                      ),
                    ),
                  ),
                ],
              );
            
        
        return const Text("There was a problem loading content.");
      ,
    );
  

然后简单地从数据中生成 DataTable 行:

      void _generateDataTableRowsForCompletedExercises(
      setNumber, weight, reps, isToFailure) 
    dataRowsForCompletedExercises.add(
      DataRow(cells: [
        DataCell(Text(setNumber.toString())),
        DataCell(Text(weight)),
        DataCell(Text(reps)),
        DataCell(
            (isToFailure == true) ? const Icon(Icons.check) : const Icon(null)),
      ]),
    );
  

【讨论】:

【参考方案2】:

我相信你的问题是你在哪里使用'then'

试试这段代码,看看打印输出

var test = await FirebaseFirestore.instance
  .collection('users')
  .doc(currentUser!.uid)
  .collection("workouts")
  .doc(workoutId)
  .collection("exercises")
  .get()
print(test);

【讨论】:

它给出了 '_JsonQuerySnapshot 的实例

以上是关于无法从嵌套集合中检索数据的主要内容,如果未能解决你的问题,请参考以下文章

删除嵌套集合中的条目

从嵌套在 Firestore 文档中的集合中获取数据的最佳方法是啥?

如何使用Mongo Java驱动程序从集合中检索随机文档

从嵌套在Firestore中的文档中的集合中获取数据的最佳方法是什么?

如何从 Firebase 同步检索数据?

Firestore 从集合中获取文档 ID