Firestore批量写入仍触发500次上限错误,求排查解决
问题根源及修复方案
核心问题
你的代码里所有写入操作都加到了同一个Batch对象里——每次batchArray.push(batch)都是把最初创建的那个batch实例重复添加,没有生成新的Batch。再加上用Promise.all并发遍历文档,计数器operationCounter被多个异步函数同时修改,完全失效,最终单个Batch的写入次数远超500,触发Firestore的限制。
具体修复步骤
- 创建新Batch实例:拆分Batch时,必须调用
firestore.batch()生成新实例,不能重复添加同一个对象。 - 替换并发遍历为顺序遍历:用
for...of替代map + Promise.all,避免多个异步函数同时操作计数器和Batch,导致计数混乱。 - 修正计数器阈值:Firestore单Batch最多支持500次写入,把阈值设为499(留余量),避免触达上限。
- 移除无效await:Batch的
update是同步操作,不需要await,去掉不影响逻辑。 - 等待Batch提交完成:最后提交所有Batch时,必须用
await,否则云函数可能提前终止,导致提交未完成。 - 优化数据读取:重复调用
doc2.data()会额外消耗资源,直接用已缓存的documentData即可。
修复后的完整代码
exports.checkSchedine2 = functions.pubsub .schedule('15,45 * * * *') .onRun(async (context) => { const currentTime = Math.floor(Date.now() / 1000); const risultatiDoc = await firestore.collection("Risultati").doc("risultati").get(); const risultatiData = risultatiDoc.data(); const schedineDocs = await firestore.collection("Schedine").get(); const batchArray = []; let currentBatch = firestore.batch(); batchArray.push(currentBatch); let operationCounter = 0; // 顺序遍历,避免并发导致计数器混乱 for (const doc of schedineDocs.docs) { const inCorsoDocs = await firestore.collection("Schedine").doc(doc.id).collection("in corso").get(); for (const doc2 of inCorsoDocs.docs) { const documentData = doc2.data(); const matches = documentData["Match"]; for (const matchId in matches) { try { const risultato = risultatiData[matchId]; // 提前跳过不满足条件的情况,减少嵌套 if (!risultato || risultato["status"] === 0 || matches[matchId]["status"] !== 0) { continue; } const bet = matches[matchId]["Bet"]; if ((bet >= 1 && bet <=3) && bet === risultato.ris) { matches[matchId]["status"] = 1; } else if (bet === 4 && risultato.goal === 1) { matches[matchId]["status"] = 1; } else if (bet === 5 && risultato.goal === 0) { matches[matchId]["status"] = 1; } else if (bet === 6 && risultato.over === 1) { matches[matchId]["status"] = 1; } else if (bet === 7 && risultato.over === 0) { matches[matchId]["status"] = 1; } else { matches[matchId]["status"] = 2; } } catch (e) { console.error("处理matchId出错:", matchId, e); } } // 执行Batch更新 currentBatch.update(doc2.ref, documentData); operationCounter++; // 操作数接近上限时,创建新Batch if (operationCounter >= 499) { currentBatch = firestore.batch(); batchArray.push(currentBatch); operationCounter = 0; } } } // 等待所有Batch提交完成 await Promise.all(batchArray.map(batch => batch.commit())); console.log("所有Batch提交完成"); });
额外优化建议
- 增加错误日志:原来的
catch (e) {}吞掉了错误,添加console.error方便排查问题。 - 减少嵌套层级:用
continue提前跳过不满足条件的循环,让代码更易读。 - 缓存
risultatiData:避免重复读取文档数据,提升性能。
内容的提问来源于stack exchange,提问作者faccio
相关产品推荐
相关产品推荐

