如何仅按日和月触发Firebase云函数发送生日通知?
解决Firebase Cloud Function生日当天发送通知的问题
你的核心问题是原代码匹配的是完整年月日,但生日只需要匹配日和月,另外原函数是HTTP触发需要手动调用,我们应该改成定时触发(每天自动运行一次)。下面分两种方案解决:
方案一:预存日月字段(推荐,查询效率更高)
在用户文档中新增一个字段,比如birthDayMonth,格式为DDMM(比如10月5日就是0510)。这样每次查询时直接匹配当前日期的DDMM即可,避免全表扫描,适合用户量较大的场景。
代码实现
const functions = require('firebase-functions'); const admin = require('firebase-admin'); const moment = require('moment'); admin.initializeApp(); // 每天凌晨0点触发(时区可根据需求调整,比如Asia/Shanghai) exports.sendBirthdayNotifications = functions.pubsub.schedule('0 0 * * *') .timeZone('Asia/Shanghai') .onRun(async (context) => { try { // 获取当前日期的DDMM格式 const todayDDMM = moment().format('DDMM'); // 查询birthDayMonth匹配今天的用户 const querySnapshot = await admin.firestore() .collection('userCollection') .where('birthDayMonth', '==', todayDDMM) .get(); if (querySnapshot.empty) { console.log('今天没有过生日的用户'); return null; } // 批量发送通知 const notificationPromises = []; querySnapshot.forEach(doc => { const tokenId = doc.data().tokenId; if (!tokenId) return; // 跳过没有设备Token的用户 const notificationContent = { notification: { title: '生日快乐!', body: '祝你今天开开心心,事事顺遂🥳', icon: 'default', sound: 'default' } }; notificationPromises.push( admin.messaging().sendToDevice(tokenId, notificationContent) .catch(err => console.error(`发送通知失败给用户${doc.id}:`, err)) ); }); await Promise.all(notificationPromises); console.log(`成功发送${notificationPromises.length}条生日通知`); return null; } catch (error) { console.error('函数执行出错:', error); return null; } });
方案二:实时过滤日月(适合小数据量)
如果不想修改用户文档结构,可以查询所有用户,然后在代码中过滤出日和月与今天匹配的用户。注意:如果用户量很大,这种方法会有性能问题,因为需要全表读取。
代码实现
const functions = require('firebase-functions'); const admin = require('firebase-admin'); const moment = require('moment'); admin.initializeApp(); exports.sendBirthdayNotifications = functions.pubsub.schedule('0 0 * * *') .timeZone('Asia/Shanghai') .onRun(async (context) => { try { const today = moment(); const todayDay = today.date(); const todayMonth = today.month() + 1; // moment的month是0-11,所以加1转为实际月份 // 获取所有用户 const querySnapshot = await admin.firestore() .collection('userCollection') .get(); if (querySnapshot.empty) { console.log('没有用户数据'); return null; } const notificationPromises = []; querySnapshot.forEach(doc => { const userData = doc.data(); const birthDate = userData.birthDate; const tokenId = userData.tokenId; if (!birthDate || !tokenId) return; // 将Firestore Timestamp转换为moment对象 const birthMoment = moment(birthDate.toDate()); const birthDay = birthMoment.date(); const birthMonth = birthMoment.month() + 1; // 匹配日和月 if (birthDay === todayDay && birthMonth === todayMonth) { const notificationContent = { notification: { title: '生日快乐!', body: '祝你今天开开心心,事事顺遂🥳', icon: 'default', sound: 'default' } }; notificationPromises.push( admin.messaging().sendToDevice(tokenId, notificationContent) .catch(err => console.error(`发送通知失败给用户${doc.id}:`, err)) ); } }); await Promise.all(notificationPromises); console.log(`成功发送${notificationPromises.length}条生日通知`); return null; } catch (error) { console.error('函数执行出错:', error); return null; } });
关键注意事项
- 时区设置:一定要设置正确的时区(比如
Asia/Shanghai),否则定时触发的时间会和预期不符。 - 设备Token有效性:发送通知前要检查
tokenId是否存在,并且可以通过sendToDevice返回的结果定期清理无效Token。 - 依赖安装:确保在函数目录下安装所需依赖:
npm install moment firebase-admin firebase-functions - 部署函数:使用Firebase CLI部署:
firebase deploy --only functions:sendBirthdayNotifications
内容的提问来源于stack exchange,提问作者Pooja
相关产品推荐
相关产品推荐

