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

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

基于Firebase的通知收件箱实现方案

通知收件箱示例

1. 数据结构设计

你原本的Post集合嵌套comment子集合的设计可以保留,在此基础上新增2个相关数据结构即可:

  • 根集合notifications,每个通知文档的字段设计如下:
    • userId:接收通知的用户UID
    • type:通知类型,此处固定为new_comment
    • postId:关联的帖子ID
    • commentId:关联的评论ID
    • content:通知预览内容,比如「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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 05:21:00