Firebase中如何在forEach循环内更新文档?(超500条场景)
Firestore批量更新文档+推送通知实现方案
问题描述
已获取符合条件的Users集合文档,需要给每个文档设置lastpush字段为当前时间,同时推送通知。不清楚如何在循环内执行更新,担心批量写入超过500条限制,纠结是否用事务。现有代码:
const pushok = await db.collection('Users') .where('aktiv', '==', 1) .where('uzemmod', '==', 1).get(); if (pushok.empty) { console.log('No matching documents.'); } else { pushok.forEach(doc => { //HERE I WOULD LIKE TO SET doc.data().lastpush: time; let payload = { notification: { title: 'Üzeneted érkezett!', body: 'Üzenet', sound: 'default', }, data: { "messageid": "1" } }; admin.messaging().sendToDevice(doc.data().notificationtoken, payload); console.log('Üzenet elküldve', doc.data().notificationtoken); }); }
解决方案
1. 循环内异步更新(最简单,适合小数据量)
直接在循环中调用doc.ref.update()更新字段,但注意forEach是同步遍历,要改用map配合Promise.all处理异步操作,避免遗漏更新:
const pushok = await db.collection('Users') .where('aktiv', '==', 1) .where('uzemmod', '==', 1).get(); const currentTime = new Date(); if (pushok.empty) { console.log('No matching documents.'); } else { // 用map生成所有异步操作的Promise const operations = pushok.docs.map(async (doc) => { // 先更新lastpush字段 await doc.ref.update({ lastpush: currentTime }); // 发送推送通知 const payload = { notification: { title: 'Üzeneted érkezett!', body: 'Üzenet', sound: 'default', }, data: { "messageid": "1" } }; await admin.messaging().sendToDevice(doc.data().notificationtoken, payload); console.log('Üzenet elküldve', doc.data().notificationtoken); }); // 等待所有操作完成 await Promise.all(operations); }
2. 分批次批量写入(适合大数据量,规避500条限制)
Firestore单批写入最多支持500个操作,当数据量超过500时,把文档分成每500个一组,分批执行批量更新:
const pushok = await db.collection('Users') .where('aktiv', '==', 1) .where('uzemmod', '==', 1).get(); const currentTime = new Date(); const batchSize = 500; const docs = pushok.docs; if (pushok.empty) { console.log('No matching documents.'); } else { // 分批次处理 for (let i = 0; i < docs.length; i += batchSize) { const batch = db.batch(); const batchDocs = docs.slice(i, i + batchSize); // 批量添加更新操作 batchDocs.forEach(doc => { batch.update(doc.ref, { lastpush: currentTime }); }); // 执行批量更新 await batch.commit(); // 发送推送通知 const notificationPromises = batchDocs.map(doc => { const payload = { notification: { title: 'Üzeneted érkezett!', body: 'Üzenet', sound: 'default', }, data: { "messageid": "1" } }; return admin.messaging().sendToDevice(doc.data().notificationtoken, payload); }); await Promise.all(notificationPromises); console.log(`批次 ${Math.floor(i/batchSize)+1} 处理完成`); } }
关于事务的说明
不需要使用事务。事务适用于需要保证多个文档更新原子性(要么全成功要么全失败)的场景,而这里每个文档的lastpush更新是独立的,没有跨文档的一致性要求,用事务反而会增加复杂度和性能开销。
内容的提问来源于stack exchange,提问作者Adrián Varga
相关产品推荐
相关产品推荐

