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

Google云函数自定义通知异常及Firestore每日数据处理方案咨询

核心问题根因

你遇到的通知偶尔触发的问题和配额无关,完全是代码的异步处理逻辑错误导致的:

  • 你在collections.forEach、snapshot.forEach里传入了async回调,但普通的forEach不会等待异步回调执行完成,外层的await collections.forEach是无效操作(forEach返回undefined,await对它没有任何作用)
  • 云函数的执行上下文在主线程同步代码执行完成后就会被回收,你代码里大量未被等待的异步操作(Firestore读写、FCM通知发送)还没执行完就被中断了,所以才会出现偶尔能触发通知、大部分时候没反应的情况
  • 你当前只有87份文档,单日全量扫描的读操作不到100次,远低于Firestore每日5万次免费读配额,云函数定时调用每日1次也远低于免费额度,完全可以在免费配额内实现需求。
代码修复方案

把所有forEach迭代替换为Promise.all+数组map的形式,确保所有异步操作都被正确等待,同时优化查询逻辑减少不必要的读操作:

import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
admin.initializeApp();
const db = admin.firestore();
const fcm = admin.messaging();

export const expiryDateChecker = functions.pubsub.schedule("0 06 * * *")
    .timeZone("Europe/London").onRun(async () => {
      const collections = await db.listCollections();
      const today = new Date();
      today.setHours(0, 0, 0, 0);
      const tomorrow = new Date(today);
      tomorrow.setDate(tomorrow.getDate() + 1);
      const afterTomorrow = new Date(tomorrow);
      afterTomorrow.setDate(afterTomorrow.getDate() + 1);

      const options = {
        priority: "high",
        timeToLive: 60 * 60 * 24,
      };

      // 用Promise.all等待所有集合处理完成
      await Promise.all(collections.map(async (collection) => {
        // 可选优化:直接加查询过滤,只查3天内到期/已过期的文档,减少读次数
        // const snapshot = await collection.where('ExpiryDate', '<', afterTomorrow).get();
        const snapshot = await collection.get();
        let amountToday = 0;
        let amountTomorrow = 0;
        let amountExpired = 0;

        // 等待所有文档处理完成
        await Promise.all(snapshot.docs.map(async (doc) => {
          const expDate = new Date(doc.data().ExpiryDate);
          const diffInTime = expDate.getTime() - today.getTime();
          const diffInDays = Math.floor(diffInTime / (1000 * 3600 * 24));

          if (diffInDays === 0) {
            amountToday++;
          } else if (diffInDays === 1) {
            amountTomorrow++;
          } else if (diffInDays < 0) {
            amountExpired++;
            try {
              const counter = parseInt(doc.data().Quantity.toString());
              const expiryDocRef = db.collection("expiryGroups").doc("Users")
                  .collection(collection.id).doc(doc.id);
              const doc2 = await expiryDocRef.get();
              if (doc2.exists) {
                // 所有写操作加await确保执行完成
                await expiryDocRef.update({Expired: true});
                const check = parseInt(doc2.data()?.expiryCount?.toString() || "0");
                if (check === 0) {
                  await expiryDocRef.update({
                    expiryCount: admin.firestore.FieldValue.increment(counter)
                  });
                }
              }
            } catch (e) {
              console.log(e);
            }
          }
        }));

        // 所有FCM发送加await,补全通知内容配置
        if (amountToday > 0) {
          const message = {
            notification: {
              title: "食品到期提醒",
              body: `${amountToday}件食品今日到期`
            }
          };
          await fcm.sendToTopic(collection.id, message, options);
        }

        if (amountTomorrow > 0) {
          const message = {
            notification: {
              title: "食品即将到期提醒",
              body: `${amountTomorrow}件食品明日到期`
            }
          };
          await fcm.sendToTopic(collection.id, message, options);
        }

        if (amountExpired > 0) {
          const message = {
            notification: {
              title: "食品已过期提醒",
              body: `${amountExpired}件食品已过期`
            }
          };
          await fcm.sendToTopic(collection.id, message, options);
        }
      }));
      return null;
    });
可选优化(进一步降低配额消耗)

如果后续数据量上涨,可以做以下优化,进一步降低资源消耗:

  • 给所有食品集合的ExpiryDate字段加索引,直接通过Firestore查询过滤出3天内到期/已过期的文档,不需要全表扫描所有文档,读操作次数会大幅降低
  • 避免调用listCollections,可以把所有用户的食品数据都放到同一个根集合下,用用户ID当文档的字段,单次查询就能拿到所有需要处理的数据,进一步减少调用次数

内容的提问来源于stack exchange,提问作者TheDude Alex Nuzum

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 15:27:04