You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase云函数实现FCM向符合条件用户推送通知代码异常排查

故障原因
  • 异步处理逻辑错误:查询用户子集合notificationTokens时未添加await关键字,且forEach遍历不会等待内部异步请求执行完成,最终得到的tokens变量为未完成的Promise或空值
  • 子集合查询结果处理错误:调用子集合的get()方法返回的是集合查询快照(可能包含多个token文档),并非单个文档对象,无法直接调用.data()方法获取字段
  • 返回值无法被正确收集:forEach方法的返回值不会被汇总为数组,无法得到所有token的集合
修正后代码
exports.sendToDevice5 = functions.firestore
    .document('Articles/{paper}')
    .onCreate(async (snapshot, context) => {
      const item = snapshot.data();
      // 只处理放射科相关子专业的文章
      if (item.subspecialty !== "RadMSK" && item.subspecialty !== "RadMS") {
        return null;
      }

      // 1. 查询所有专业为放射科的用户
      const radiologyUsersSnapshot = await admin.firestore().collection('users').where("specialty", "==", "RADIOLOGY").get();
      if (radiologyUsersSnapshot.empty) {
        return null;
      }

      // 2. 批量查询所有用户的通知token
      const tokenPromises = [];
      radiologyUsersSnapshot.forEach(userDoc => {
        tokenPromises.push(
          admin.firestore().collection('users').doc(userDoc.id).collection('notificationTokens').get()
        );
      });
      const tokenSnapshots = await Promise.all(tokenPromises);

      // 3. 收集所有有效token
      const tokens = [];
      tokenSnapshots.forEach(tokenSnapshot => {
        tokenSnapshot.forEach(tokenDoc => {
          if (tokenDoc.data().token) {
            tokens.push(tokenDoc.data().token);
          }
        });
      });

      if (tokens.length === 0) {
        return null;
      }

      // 4. 构造推送 payload
      const payload = {
        notification: {
          title: `${item.title}!`,
          body: `New Journal`,
          sound: "default",
        },
        data: {click_action: 'FLUTTER_NOTIFICATION_CLICK'},
      };

      // 5. 推送通知,可选添加结果处理逻辑,删除无效token
      const response = await admin.messaging().sendToDevice(tokens, payload);
      // 以下为可选的无效token清理逻辑
      const invalidTokens = [];
      response.results.forEach((result, index) => {
        const error = result.error;
        if (error) {
          if (error.code === 'messaging/invalid-registration-token' || 
              error.code === 'messaging/registration-token-not-registered') {
            invalidTokens.push(tokens[index]);
          }
        }
      });
      // 这里可以添加代码删除数据库中存储的无效token

      return response;
    });
补充说明
  • 代码新增了空结果判断,避免无匹配用户时出现空指针错误
  • 可选添加的无效token清理逻辑可以减少后续无效推送的请求,降低FCM接口报错概率
  • 如果推送用户量超过1000,建议做分批推送,避免触发FCM接口限制

内容的提问来源于stack exchange,提问作者Kaveshan Naidoo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 02:06:03