Firestore文档内嵌集合更新求助:子习惯数据重复问题
问题描述
- 点击父习惯后,标识为1的子习惯本应仅存在于
subHabits集合下,却在顶级habits集合中出现重复文档 - 预期更新
subHabits集合中子习惯1的elapsedDuration字段 - 实际仅更新了顶级
habits集合中的1文档,且该文档仅在点击暂停按钮时才创建 - 怀疑是
toggleSubHabitStatus方法导致问题,希望修改后仅更新父习惯的subHabits集合,不在顶级habits中生成重复文档
问题根源与修复方案
1. 核心问题:重复执行更新逻辑
按钮点击事件中同时调用了_startTimer/_pauseTimer和toggleSubHabitStatus,而这两个方法内部都包含状态切换与Firestore更新操作,导致重复修改,甚至触发意外的文档创建。
2. 具体修复步骤
步骤1:移除重复的方法调用
修改按钮点击逻辑,只保留_startTimer或_pauseTimer调用(这两个方法已包含完整的状态更新与Firestore操作):
GestureDetector( onTap: () { if (_isTimerRunning) { _pauseTimer(widget.subHabit, _elapsedTime); } else { _startTimer(); } // 移除该行重复调用:toggleSubHabitStatus(widget.subHabit); }, // 其余代码保持不变 )
步骤2:统一更新逻辑(可选优化)
将分散的Firestore更新逻辑整合到toggleSubHabitStatus,避免代码冗余:
void toggleSubHabitStatus(SubHabit subHabit, int elapsedSeconds) { _toggleStarted(subHabit); final subHabitRef = FirebaseFirestore.instance .collection('habits') .doc(subHabit.parentHabitId) .collection('subHabits') .doc(subHabit.id); subHabitRef .update({'elapsedDuration': elapsedSeconds}) .then((_) => print('SubHabit updated successfully')) .catchError((error) => print('Failed to update subHabit: $error')); }
然后在_startTimer和_pauseTimer中替换原更新代码:
// _startTimer内替换原更新逻辑 toggleSubHabitStatus(widget.subHabit, _elapsedTime.inSeconds); // _pauseTimer内替换原更新逻辑 toggleSubHabitStatus(subHabit, _elapsedSeconds);
步骤3:规范状态修改方式
不要直接修改传入的widget.subHabit(不符合Flutter状态管理规范),在本地维护子习惯的状态副本:
// 在State类中添加本地状态变量 late SubHabit _localSubHabit; @override void initState() { super.initState(); _elapsedTime = widget.subHabit.elapsedDuration; // 复制传入的子习惯到本地状态 _localSubHabit = widget.subHabit.copyWith(); } // 修改_toggleStarted方法,操作本地状态 void _toggleStarted() { setState(() { _localSubHabit.isStarted = !_localSubHabit.isStarted; }); }
同时给SubHabit类添加copyWith方法,方便对象复制:
class SubHabit { final String id; final String parentHabitId; final String name; final Duration elapsedDuration; final bool isStarted; SubHabit({ required this.id, required this.parentHabitId, required this.name, required this.elapsedDuration, required this.isStarted, }); // 添加copyWith方法 SubHabit copyWith({ String? id, String? parentHabitId, String? name, Duration? elapsedDuration, bool? isStarted, }) { return SubHabit( id: id ?? this.id, parentHabitId: parentHabitId ?? this.parentHabitId, name: name ?? this.name, elapsedDuration: elapsedDuration ?? this.elapsedDuration, isStarted: isStarted ?? this.isStarted, ); } // 原toMap方法保持不变 Map<String, dynamic> toMap() { return { 'id': id, 'parentHabitId': parentHabitId, 'name': name, 'elapsedDuration': elapsedDuration.inSeconds, 'isStarted': isStarted, }; } }
步骤4:清理错误文档
手动删除Firestore顶级habits集合中错误创建的子习惯文档,确保后续操作仅针对subHabits子集合。
内容的提问来源于stack exchange,提问作者Leena Marie
相关产品推荐
相关产品推荐

