如何基于Firebase实现Web应用非FCM模式的通知收件箱
基于Firebase的通知收件箱实现方案

1. 数据结构设计
你原本的Post集合嵌套comment子集合的设计可以保留,在此基础上新增2个相关数据结构即可:
- 根集合
notifications,每个通知文档的字段设计如下:userId:接收通知的用户UIDtype:通知类型,此处固定为new_commentpostId:关联的帖子IDcommentId:关联的评论IDcontent:通知预览内容,比如「XXX在你的帖子《XXX》下发布了新评论」isRead:布尔值,默认false代表未读createTime:通知生成时间,用于列表排序
- 根集合
users,每个用户文档新增unreadNotificationCount数字字段,默认值为0,存储当前用户的未读通知总数
2. 核心功能实现步骤
2.1 新评论发布时自动生成通知
使用Firebase Cloud Functions后台触发,避免前端篡改数据,示例代码如下:
const functions = require('firebase-functions'); const admin = require('firebase-admin'); admin.initializeApp(); // 监听所有帖子下的新评论创建事件 exports.sendCommentNotification = functions.firestore .document('posts/{postId}/comments/{commentId}') .onCreate(async (snap, context) => { const commentData = snap.data(); const postId = context.params.postId; // 查询对应帖子的作者UID const postDoc = await admin.firestore().collection('posts').doc(postId).get(); const postAuthorId = postDoc.data().authorId; // 排除用户自己评论自己帖子的场景 if (commentData.authorId === postAuthorId) return null; // 创建通知文档 await admin.firestore().collection('notifications').add({ userId: postAuthorId, type: 'new_comment', postId: postId, commentId: context.params.commentId, content: `${commentData.authorName}在你的帖子《${postDoc.data().title}》下发布了新评论`, isRead: false, createTime: admin.firestore.FieldValue.serverTimestamp() }); // 对应用户的未读通知数+1 await admin.firestore().collection('users').doc(postAuthorId).update({ unreadNotificationCount: admin.firestore.FieldValue.increment(1) }); return null; });
2.2 用户登录时展示未读通知数
前端用onSnapshot实时监听当前用户的未读数字段,自动更新页面展示:
// 用户登录完成后获取当前用户UID const uid = auth.currentUser.uid; // 监听未读数变更 db.collection('users').doc(uid).onSnapshot(doc => { const unreadCount = doc.data().unreadNotificationCount || 0; // 此处将unreadCount渲染到页面的通知图标角标位置即可 });
2.3 已读/未读状态管理+未读数清零
用户点击打开通知收件箱时,批量标记所有未读通知为已读,同时清零未读数:
async function markAllAsRead(uid) { const batch = db.batch(); // 查询当前用户所有未读通知 const unreadNotifs = await db.collection('notifications') .where('userId', '==', uid) .where('isRead', '==', false) .get(); // 批量更新所有未读通知为已读 unreadNotifs.forEach(doc => { batch.update(doc.ref, { isRead: true }); }); // 未读数清零 batch.update(db.collection('users').doc(uid), { unreadNotificationCount: 0 }); // 提交批量操作 await batch.commit(); }
2.4 通知收件箱列表加载
按时间倒序拉取当前用户的所有通知,支持分页:
async function loadNotificationList(uid, pageSize = 20) { const notifsSnapshot = await db.collection('notifications') .where('userId', '==', uid) .orderBy('createTime', 'desc') .limit(pageSize) .get(); return notifsSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); }
注意事项
- 如果需要支持评论中@特定用户发送通知,只需要在云函数中解析评论内容的@用户ID,给对应ID的用户也新增通知文档即可
- 历史通知可以设置定时清理规则,比如自动删除3个月以上的已读通知,减少存储占用
- 通知列表建议做分页加载,避免一次性拉取过多历史数据影响性能
内容的提问来源于stack exchange,提问作者Min
相关产品推荐
相关产品推荐

