Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to structure database for unread item alerts per user

I just have a general database theory question. I have a need to make something similar to showing what posts/items a user has viewed or not (such as in a forum) or an unread email message. What I have is there are posts that multiple users can view, but it needs to separate by user who has actually viewed it. So if User A viewed Post 1, it would no longer show that Post 1 is a new item to view, but to User B, it would still show that Post 1 is a new item to view.

I've search for other ideas and one of them is to get a timestamp of when the user last logged in, but I actually need to keep track of the posts they've seen as opposed to posts that have happened since they last logged in.

I would like a MySQL database solution if possible, but I'm open to cookies if that is a must. I could do this on my own and just figure it out, but I'd appreciate any advice on how to properly structure a table(s) to make this the most efficient. Also, bandwidth and storage is not issue.

like image 948
n0nag0n Avatar asked Jun 08 '12 16:06

n0nag0n


3 Answers

While reviewing the relevant schema for phpBB, I found the following:

# Table: 'phpbb_topics_track'
CREATE TABLE phpbb_topics_track (
    user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    topic_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    forum_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    mark_time int(11) UNSIGNED DEFAULT '0' NOT NULL,
    PRIMARY KEY (user_id, topic_id),
    KEY topic_id (topic_id),
    KEY forum_id (forum_id)
) CHARACTER SET `utf8` COLLATE `utf8_bin`;

And:

# Table: 'phpbb_forums_track'
CREATE TABLE phpbb_forums_track (
    user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    forum_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    mark_time int(11) UNSIGNED DEFAULT '0' NOT NULL,
    PRIMARY KEY (user_id, forum_id)
) CHARACTER SET `utf8` COLLATE `utf8_bin`;

Then I look here in their wiki:

This table keeps record for visited topics in order to mark them as read or unread. We use the mark_time timestamp in conjunction with last post of topic x's timestamp to know if topic x is read or not.

In order to accurately tell whether a topic is read, one has to also check phpbb_forums_track.

So essentially they have a lookup table to store the data associated with a user's viewing of a topic (thread), and then check it against the timestamp in the forum view table, to determine whether the topic has been viewed by the user.

like image 135
Jared Farrish Avatar answered Oct 16 '22 18:10

Jared Farrish


Just create a simple cross-reference table (read_posts or something):

user_id|post_id
----------------
2      | 132
53     | 43
....

Make sure that both of these columns are indexed (especially important that the user_id be indexed) and then use a join (or a sub-query) to select unread posts for the logged in user. If you're just trying to show a list of unread posts, for example, you just run:

SELECT * FROM `posts` WHERE `post_id` NOT IN (
    SELECT `post_id` FROM `read_posts` WHERE `user_id`='[$USER ID]')
ORDER BY [your ordering clause]
like image 2
Ben D Avatar answered Oct 16 '22 19:10

Ben D


Based on this description I would use a simple table with maybe 3 columns.

  1. User ID
  2. Post ID
  3. Timestamp First Viewed

When a user views a post, add a row to the table. If a row does not exist in the table for a given user/post id combo, then they have not viewed the post.

like image 1
colonelclick Avatar answered Oct 16 '22 18:10

colonelclick