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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 18:28:11