如何防止Firestore数值字段变为负数并获取更新前的原始值
解决方案
方案1:客户端事务+前置校验(推荐)
直接读取目标文档的当前shares值做校验,同时用Firestore事务保证操作原子性,避免并发更新导致的数据不一致问题。
修正后的代码如下:
function sellStock() { // 先匹配到对应股票的文档ID db.collection("Stocks") .where("ticker", "==", props.name) .get() .then((querySnapshot) => { if (!querySnapshot.empty) { querySnapshot.forEach(async function (doc) { const stockRef = db.collection("myStocks").doc(doc.id); // 开启事务做原子校验+更新 try { await db.runTransaction(async (t) => { const stockDoc = await t.get(stockRef); // 此处获取的就是更新前的旧持仓数量 const currentShares = stockDoc.data().shares; // 前置校验,持仓不足直接抛出错误终止更新 if (currentShares < amount) { throw new Error("持仓数量不足,无法卖出"); } // 校验通过执行更新 t.update(stockRef, { shares: currentShares - amount }); }); console.log("卖出操作执行成功"); } catch (e) { console.log("操作失败:", e.message); } }); } }); }
方案2:Firestore安全规则兜底(必加)
即使客户端被恶意篡改,安全规则也会拦截非法的更新请求,从服务端层面保证shares不会为负,规则配置如下:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /myStocks/{stockId} { allow update: if request.resource.data.shares >= 0 && request.resource.data.shares <= resource.data.shares; } } }
注意事项
- 事务的作用是防止多个卖出请求同时执行时,先查出来的持仓还没更新,导致最后计算结果为负的并发问题
- 两种方案建议同时使用:客户端校验降低无效请求,安全规则做最终兜底
内容的提问来源于stack exchange,提问作者BarakOren
相关产品推荐
相关产品推荐

