通知系统里的系统公告该怎么存储用户是否已读

业务场景

  1. 想做一个类似阿里云的通知系统,一条系统公告只存一条数据,用户量大的话,怎么存储用户是否已读系统公告
  2. 用户首页看到的这个未读消息数目该怎么维护

个人想法

  1. 用 Redis bitmap 存每条公告哪些用户是否已读
  2. 用 Redis string 字段维护每个用户未读数,插入系统公告之后,全部扫一遍 incr 1?

不解

是怎么做到列表中未读的消息按时间顺序排列出来的
难道是用数据库每条公告关联所有用户?

您期望得到的结果?

问问各位有这方面的业务经验吗?
或是发表一下自己的看法?

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
最佳答案

两个表

  • notice 通知表
    字段
    id
    content
    created_at
  • notice_read 已读状态表
    字段
    user_id
    notice_id

用户已读向 notice_read 表添加一条数据 (可以同时使用redis bitmap 存储已读状态) 查询未读 可以查询 notice 总数 减去 notice_read 对应用户的数据总数 (当然也可以用缓存存储) 具体需求看自己怎么设计吧,数据量小用数据库也没关系

  • 时间排列可以 created_at 倒序

  • 有问题欢迎大佬纠正

10个月前 评论
讨论数量: 9

公告存储再一张表,用户是否读取公告再存储一张表。读了就记录在用户公告表插入已读公告,取出来和公告表对比。就能判断是否已读。未读数量直接相减即可!

10个月前 评论
fansheng (楼主) 10个月前

用户多了估计会存单独用户的已读id

10个月前 评论

如果是我来做基本上也会是和1楼1样的做法 插眼看看有没有大佬有更好的方法

10个月前 评论

首先排除楼主把读取状态存内存的想法,因为要保存每个用户对每个公告的读取状态,需要保存 n * m 条数据,随着用户量增长和公告数量增长,数据比较庞大,然后又要保证永久在内存存储,有点不靠谱

10个月前 评论
sanders

没想出来为何不直接使用一张表来存储消息。如果考虑到用户量,可以按用户主键哈希进行分表或者加上索引之后分区,然后通过仓库模式或封装服务来确保查询必含用户条件,来减少跨表或跨区查询。

“是怎么做到列表中未读的消息按时间顺序排列出来的” 按时间排序,暂时没想到其他的。

“难道是用数据库每条公告关联所有用户” 应该是公告和消息分两张表存储,用户看到的是“公告类型”的消息,用户消息可多态关联到公告中。

10个月前 评论

两个表

  • notice 通知表
    字段
    id
    content
    created_at
  • notice_read 已读状态表
    字段
    user_id
    notice_id

用户已读向 notice_read 表添加一条数据 (可以同时使用redis bitmap 存储已读状态) 查询未读 可以查询 notice 总数 减去 notice_read 对应用户的数据总数 (当然也可以用缓存存储) 具体需求看自己怎么设计吧,数据量小用数据库也没关系

  • 时间排列可以 created_at 倒序

  • 有问题欢迎大佬纠正

10个月前 评论

用数据表做

  1. 首先消息分为全体消息和单独私信,可以用2个表或者1个表增加类型区分
  2. 全体消息可不关联用户,指定私信的加一个表,一对多关联用户
  3. 如果2个表,查询所有消息用union all 连接即可
  4. 已读,私信就是修改状态,全体消息就是增加数据
  5. 未读数是所有消息和单独私信的未读书的总和,相加即可,
  6. 未读数具体怎么算,我用到的和上面提到的算法一致,求出消息总数和已读总数相减,只不过我把未读消息数存到了redis,有新公告就清楚所有缓存,有私信就重新计算此用户的未读数,因为点进去就默认全部已读,所以出错了也没什么影响。
  7. 已读,私信就是在关联表修改状态,全体消息就是增加一条数据
  8. 还有一种做法是,用户通过某些特定的行为,比如说登录,或者说任意网络请求,将全体消息也像单独私信一样绑定给用户,

具体怎么做要看自己的用户量和业务需求,历史公告等内容,新注册的用户是否可见等等。

10个月前 评论
fansheng (楼主) 10个月前

已在线上使用多次,做点补充。

两表法
1.通知表.(notice)

列名 说明
id 序号
created_at 创建时间

2.已读状态表(notice_read).

列名 说明
id 序号
notice_id 公告序号
user_id 用户序号
read_at 读公告时间

应用
1 当有公告时,插入 notice 即可,不用做其他操作。
2 当用户登录或刷新页面时,查询 notice 表与 notice_read,检查是否有未读通知。通过 noticenotice_read 相减可得有多少条未读以及是哪些条未读。
3 当用户点开公告阅读时,在 notice_read 中记录读了哪条以及时间。

这样的话,不管用户基数有多大, notice 表本身只存公告,条目比较少。notice_read 只存用户已读的条目,也不会大。
也可以实现例如某个公告所有用户可查看,比如引导;某些公告过期了不需要查看,比如新年祝贺。都在步骤2中实现即可。

对于一些用户基数大但活跃用户少的站点尤其好用。

10个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!