Flutter新手求助:如何向Firestore同一文档ID中添加更多Exercise数据
解决向Firestore同一文档添加多个Exercise数据的问题
刚接触Flutter和Firestore确实容易踩这类小坑,你现在的代码是每次生成新文档来存储单个Exercise,但我们的目标是在同一个文档里累积多个Exercise实例,下面一步步帮你调整实现:
核心思路
我们可以给workouts集合的文档添加一个exercises数组字段,把每个Exercise实例转成Map后存在这个数组里。借助Firestore的FieldValue.arrayUnion()方法,就能安全地向数组追加新元素,不会覆盖原有数据。
步骤1:完善Exercise类的Firestore转换逻辑
首先要确保Exercise能正确转成Firestore支持的数据格式,尤其是日期要转成Timestamp(Firestore不直接存储DateTime类型),参考这个实现:
class Exercise { final DateTime date; final String name; final List<String> reps; final List<String> weight; Exercise({ required this.date, required this.name, required this.reps, required this.weight, }); // 转成Firestore可存储的Map Map<String, dynamic> toFirestore() { return { 'date': Timestamp.fromDate(date), 'name': name, 'reps': reps, 'weight': weight, }; } // 可选:从Firestore数据转回Exercise实例 factory Exercise.fromFirestore(Map<String, dynamic> data) { return Exercise( date: (data['date'] as Timestamp).toDate(), name: data['name'], reps: List<String>.from(data['reps']), weight: List<String>.from(data['weight']), ); } }
步骤2:初始化新的训练记录文档(第一次创建)
如果要新建一个训练记录并添加第一个Exercise,记得保存生成的文档ID,后续追加Exercise要用到这个ID:
// 生成新文档ID并保存下来(可以存在本地变量或SharedPreferences里) String workoutDocId = FirebaseFirestore.instance.collection('workouts').doc().id; // 创建第一个Exercise实例 final firstExercise = Exercise( date: DateTime.now(), name: 'Leg', reps: ['1', '2'], weight: ['50', '40'], ); // 初始化文档,包含exercises数组和其他你需要的字段 FirebaseFirestore.instance .collection('workouts') .doc(workoutDocId) .set({ 'exercises': [firstExercise.toFirestore()], 'createdAt': Timestamp.fromDate(DateTime.now()), // 可选:添加训练记录创建时间 'workoutName': '我的腿部训练', // 可选:给训练记录起个名字 }) .then((_) => print('训练记录初始化成功!')) .catchError((err) => print('初始化失败:$err'));
步骤3:向已有训练记录追加新Exercise
当需要给同一个训练记录添加更多Exercise时,使用之前保存的workoutDocId,调用update方法结合arrayUnion追加元素:
// 这里传入你之前保存的训练记录文档ID String targetWorkoutId = workoutDocId; // 也可以直接写具体的ID字符串 // 创建新的Exercise实例 final newExercise = Exercise( date: DateTime.now(), name: 'Chest', reps: ['3', '4'], weight: ['60', '55'], ); // 向目标文档的exercises数组追加新元素 FirebaseFirestore.instance .collection('workouts') .doc(targetWorkoutId) .update({ 'exercises': FieldValue.arrayUnion([newExercise.toFirestore()]) }) .then((_) => print('新Exercise添加成功!')) .catchError((err) => print('添加失败:$err'));
额外提示
- 如果不确定目标文档是否存在,可以用
set搭配SetOptions(merge: true),这样文档不存在时会自动创建,存在时会合并更新:FirebaseFirestore.instance .collection('workouts') .doc(targetWorkoutId) .set( {'exercises': FieldValue.arrayUnion([newExercise.toFirestore()])}, SetOptions(merge: true), ); arrayUnion会自动忽略数组中完全相同的元素,如果允许重复添加,这个方法完全适用;如果要避免重复,可以先查询文档中的exercises数组,判断是否已存在目标元素再执行添加操作。
内容的提问来源于stack exchange,提问作者Jesper Egsgaard Nielsen
相关产品推荐
相关产品推荐

