如何让Cloud Function在Firestore重复写入时仅触发一次?
解决Firestore云函数触发两次推送通知的问题
解决这个问题有几种可行的方案,具体如下:
方法一:通过路径参数与文档内容匹配过滤
你的云函数监听/messages/{toUid}/{fromUid}/{id}路径,每次创建的两个文档中,只有接收方对应的文档会满足「路径参数toUid与文档内toId一致」的条件(发送方的文档中toUid是发送者ID,和toId不符)。在函数开头添加判断,仅处理符合条件的文档即可:修改后的代码片段:
exports.messageNotificationsTrigger = functions .region('europe-west2') .firestore .document('/messages/{toUid}/{fromUid}/{id}') .onCreate(async (snap, context) => { const db = admin.firestore(); const data = snap.data(); const toId = data.toId; // 新增判断:仅处理接收方的文档 if (context.params.toUid !== toId) { return null; // 跳过发送方文档的触发 } const message = data.text; const fromId = data.fromId; const fromUserName = data.fromUserName; const userReference = db.collection("tokens").doc(`${toId}`); const userToSend = await userReference.get(); if (!userToSend.exists) { functions.logger.error("No such user", toId); return; } else { const userData = userToSend.data(); const token = userData?.notificationToken; // Notification payload const payload = { notification: { title: fromUserName, body: message, }, data : { "mutable-content": "1" } }; // 补充发送推送的逻辑,例如:await admin.messaging().sendToDevice(token, payload) } });方法二:给消息文档添加标记字段
发送消息时,给接收方的文档添加isNotificationTarget: true标记,发送方的文档设为false。云函数触发时先检查该字段,仅处理标记为true的文档:发送消息的逻辑示例:
// 发送方文档 await db.collection('messages').doc(senderId).doc(receiverId).doc(messageId).set({ text: message, toId: receiverId, fromId: senderId, fromUserName: senderName, isNotificationTarget: false }); // 接收方文档 await db.collection('messages').doc(receiverId).doc(senderId).doc(messageId).set({ text: message, toId: receiverId, fromId: senderId, fromUserName: senderName, isNotificationTarget: true });云函数中的判断:
exports.messageNotificationsTrigger = functions .region('europe-west2') .firestore .document('/messages/{toUid}/{fromUid}/{id}') .onCreate(async (snap, context) => { const data = snap.data(); // 检查标记字段,非目标文档直接跳过 if (!data.isNotificationTarget) { return null; } // 后续原有逻辑... });方法三:优化消息存储结构(长期推荐)
双向存储相同消息会造成数据冗余,可改为单份存储:将消息存在messages/{messageId},再在每个用户的userMessages/{userId}集合中存储消息的引用或元数据(如messageId、senderId、timestamp)。此时云函数只需监听userMessages中接收方的文档创建事件,从根源避免重复触发。不过该方案需要调整前后端的消息读写逻辑,适合重构时采用。
内容的提问来源于stack exchange,提问作者URihal
相关产品推荐
相关产品推荐

