Firebase云函数onUpdate触发时的Firestore读取量及重复执行疑问
Firebase Cloud Functions onUpdate触发器:读取负载与重复执行问题
问题描述
在Firebase控制台观察到大量读取操作,怀疑源自我的「推荐函数」。该函数运行正常,但担心应用扩容时会产生极高读取负载。核心问题:
- 每次触发该函数时,是否会产生等同于users集合用户数量的读取量?
- 作为onUpdate触发器函数,是否会在每次文档更新时重复执行任务?
此外,希望获取该主题的相关资源,Firebase官网说明不够清晰。
附上函数代码:
export const onReferralInfoUpdate = functions. firestore.document('users/{userUid}') .onUpdate(async (change, context) => { const before = change.before.data(); const after = change.after.data(); const currentUserUid = after["uid"]; if (before.godfather_code == after.godfather_code){ console.log('Text did not change') return null } const godfatherUserSnapshot = await db.collection('users').where("referral_code", "==", after.godfather_code).get(); const godfather = godfatherUserSnapshot.docs[0].data(); const godfatherUid = godfather["uid"]; const userRef = db.collection('users').doc(after.uid); const godfather_code = after.godfather_code await userRef.update({godfather_code}) console.log(`the text before was >> ${before.godfather_code} << and after is ${after.godfather_code}` ) let batch = db.batch(); const updateGodfather = db.collection('users').doc(godfatherUid); batch.update(updateGodfather, { reward: admin.firestore.FieldValue.increment(100), godChildUid: admin.firestore.FieldValue.arrayUnion(currentUserUid), }); return batch.commit(); });
解答
问题1:每次触发的读取量是否等于users集合总用户数?
不会。你的函数产生的读取量由以下几部分构成:
- Firestore onUpdate触发器触发时,会自动读取更新前后的用户文档(
change.before和change.after),这会产生2次读取操作。 - 查询推荐码对应的教父用户:
db.collection('users').where("referral_code", "==", after.godfather_code).get()。如果referral_code字段已创建单字段索引,这个查询只会读取匹配到的文档(通常是1个,因为推荐码应该唯一),而非整个users集合的所有文档。
所以每次触发函数的总读取量是2 + N(N为查询匹配的文档数,通常是1),远小于users集合的总用户数。
问题2:onUpdate触发器是否会在每次文档更新时重复执行?
是的,但你的函数已做了部分限制:
- onUpdate触发器会在
users/{userUid}文档的任何字段更新时触发,但你的函数里通过if (before.godfather_code == after.godfather_code)判断,只有当godfather_code字段发生变化时才会继续执行逻辑,否则直接返回null终止函数。 - 注意:你的函数里有一个严重的问题——
await userRef.update({godfather_code})这行代码会再次更新当前用户的godfather_code字段(即使值和当前一致),这会再次触发onUpdate触发器,导致函数额外执行一次。虽然第二次执行会因为before.godfather_code == after.godfather_code而终止,但这会产生不必要的读取操作(触发器的两次文档读取),这很可能是你观察到大量读取的原因之一。
优化建议
立即移除await userRef.update({godfather_code})这行代码:因为after.godfather_code已经是文档更新后的最新值,你不需要再次更新该字段,这完全是冗余操作,还会触发额外的触发器执行。
相关资源提示
- Firestore触发器执行逻辑:onUpdate触发器仅在文档内容发生变化时触发,若文档字段值未实际改变(即使调用了update),也会触发触发器。
- Firestore读取量计算:带索引的查询仅按返回的文档数量计费,而非扫描的文档数量;触发器快照的文档读取会计入读取量。
- 触发器循环避免:禁止在触发器函数中更新触发该函数的原文档,除非有明确的终止条件(如你的字段变化判断),否则可能导致无限循环或不必要的重复执行。
- 批量操作:使用
batch进行多文档写入可以减少网络请求次数,你的代码中使用batch的方式是正确的。
内容的提问来源于stack exchange,提问作者Mike_Baltimore
相关产品推荐
相关产品推荐

