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

在Firestore中添加已完成瑜伽练习时计算总时长与卡路里的方法

解决Firestore添加练习时计算总时长与总卡路里的方案

核心思路

不在每次加载时从练习数组中实时求和(数组量大时效率低下),而是直接在文档中维护total_time和total_kcal两个字段,每次添加新练习时同步更新这两个总和值。根据当日文档是否存在分两种处理逻辑,同时兼顾并发场景下的数据一致性。


1. 低并发场景:客户端直接读写(适合单人使用或低频次操作)

先查询当日文档,根据存在状态执行创建或更新操作:

// 生成当日文档ID(格式如"2024-05-20")
const dateDocId = new Date().toISOString().split('T')[0];
// 新完成的练习数据
const newWorkout = { duration: 30, kcal: 150, name: "基础流瑜伽" };
// 获取Firestore文档引用
const docRef = db.collection('dailyWorkouts').doc(dateDocId);

docRef.get().then(doc => {
  if (!doc.exists) {
    // 当日无文档,创建新文档并初始化总和
    return docRef.set({
      workouts: [newWorkout],
      total_time: newWorkout.duration,
      total_kcal: newWorkout.kcal
    });
  } else {
    // 读取现有总和,计算新值
    const currentTotalTime = doc.data().total_time || 0;
    const currentTotalKcal = doc.data().total_kcal || 0;
    const newTotalTime = currentTotalTime + newWorkout.duration;
    const newTotalKcal = currentTotalKcal + newWorkout.kcal;
    
    // 更新文档:添加新练习到数组,同步更新总和
    return docRef.update({
      workouts: firebase.firestore.FieldValue.arrayUnion(newWorkout),
      total_time: newTotalTime,
      total_kcal: newTotalKcal
    });
  }
}).catch(error => {
  console.error("更新练习记录失败:", error);
});

注意事项

  • 用arrayUnion可避免重复添加同一练习(若允许重复提交,改用arrayAppend)
  • 加|| 0处理旧数据可能缺失总和字段的情况,防止出现NaN

2. 高并发场景:使用Firestore事务(保证数据原子性)

如果存在同一用户快速多次点击「完成」,或多用户共享当日文档的情况,直接读写可能导致总和计算错误。用事务确保读操作和写操作的原子性:

const dateDocId = new Date().toISOString().split('T')[0];
const newWorkout = { duration: 30, kcal: 150, name: "基础流瑜伽" };
const docRef = db.collection('dailyWorkouts').doc(dateDocId);

db.runTransaction(transaction => {
  // 事务内先获取文档
  return transaction.get(docRef).then(doc => {
    if (!doc.exists) {
      // 事务中创建新文档
      transaction.set(docRef, {
        workouts: [newWorkout],
        total_time: newWorkout.duration,
        total_kcal: newWorkout.kcal
      });
    } else {
      const currentTotalTime = doc.data().total_time || 0;
      const currentTotalKcal = doc.data().total_kcal || 0;
      const newTotalTime = currentTotalTime + newWorkout.duration;
      const newTotalKcal = currentTotalKcal + newWorkout.kcal;
      
      // 事务中更新文档,确保操作原子性
      transaction.update(docRef, {
        workouts: firebase.firestore.FieldValue.arrayUnion(newWorkout),
        total_time: newTotalTime,
        total_kcal: newTotalKcal
      });
    }
  });
}).then(() => {
  console.log("练习记录更新成功");
}).catch(error => {
  console.error("事务执行失败:", error);
});

优势

事务会自动处理冲突:如果事务执行期间文档被其他操作修改,Firestore会重试事务逻辑,确保总和计算准确。


内容的提问来源于stack exchange,提问作者Vaibhav Tiwari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:37:44