在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
相关产品推荐
相关产品推荐

