我目前正在创建一个类似于 Reddit 的社交媒体平台。我希望我的用户能够日复一日地滚动浏览他们的主页,并且不会多次看到同一篇帖子,就像在 Reddit 或 Twitter 上一样。解决这个问题的最佳方法是什么?
我正在考虑创建一个表来存储每个用户的帖子查看历史记录,每当用户获取帖子时,我都会确保返回给用户的帖子都不在该特定用户的查看历史记录中。然而,我有两个主要担忧。
存储每个用户及其查看的每个帖子的查看后历史记录将导致大量条目。
每次任何用户想要在其主页上获取帖子时,都会将每个帖子与非常大的表进行比较,以确保用户还没有该帖子。
这是迄今为止我的数据库结构:
--@block
CREATE TABLE `users` (
`uid` varchar(255) NOT NULL,
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`quote` varchar(255) DEFAULT NULL,
PRIMARY KEY (`uid`),
UNIQUE KEY `username` (`username`),
CONSTRAINT `username_format` CHECK (
regexp_like(`username`, _utf8mb4 '^[A-Za-z0-9_]+$')
)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci;
--@block
CREATE TABLE `posts` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) NOT NULL,
`title` varchar(255) NOT NULL,
`body` text NOT NULL,
`timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `fk_posts_users` (`user_id`),
CONSTRAINT `fk_posts_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`uid`) ON DELETE CASCADE
) ENGINE = InnoDB AUTO_INCREMENT = 16 DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci;
--@block
CREATE TABLE `comments` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`post_id` int NOT NULL,
`parent_comment_id` int DEFAULT NULL,
`content` text,
`timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `fk_comments_users` (`user_id`),
KEY `fk_comments_posts` (`post_id`),
KEY `fk_comments_comments` (`parent_comment_id`),
CONSTRAINT `fk_comments_comments` FOREIGN KEY (`parent_comment_id`) REFERENCES `comments` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_comments_posts` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_comments_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`uid`) ON DELETE
SET NULL
) ENGINE = InnoDB AUTO_INCREMENT = 9 DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci;
--@block
CREATE TABLE `tags` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE = InnoDB AUTO_INCREMENT = 4 DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci;
--@block
CREATE TABLE `post_tags` (
`post_id` int NOT NULL,
`tag_id` int NOT NULL,
PRIMARY KEY (`post_id`, `tag_id`),
KEY `fk_post_tags_tags` (`tag_id`),
CONSTRAINT `fk_post_tags_posts` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_post_tags_tags` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci;
--@block
CREATE TABLE `post_votes` (
`post_id` int NOT NULL,
`user_id` varchar(255) NOT NULL,
`vote_type` enum('upvote', 'downvote') NOT NULL,
PRIMARY KEY (`post_id`, `user_id`),
KEY `fk_post_votes_users` (`user_id`),
CONSTRAINT `fk_post_votes_posts` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_post_votes_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`uid`) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci;
--@block
CREATE TABLE `comment_votes` (
`comment_id` int NOT NULL,
`user_id` varchar(255) NOT NULL,
`vote_type` enum('upvote', 'downvote') NOT NULL,
PRIMARY KEY (`comment_id`, `user_id`),
KEY `fk_comment_votes_users` (`user_id`),
CONSTRAINT `fk_comment_votes_comments` FOREIGN KEY (`comment_id`) REFERENCES `comments` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_comment_votes_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`uid`) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci;
CREATE TABLE `post_views` (
`post_id` int NOT NULL,
`user_id` varchar(255) NOT NULL,
PRIMARY KEY (`post_id`, `user_id`),
KEY `fk_post_views_users` (`user_id`),
CONSTRAINT `fk_post_views_posts` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_post_views_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`uid`) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci;
偏离主题,但是,当我显示任何帖子或评论时,我还需要显示该帖子或评论的作者的用户名。我正在考虑将用户表中的用户名列作为主键,因为它是唯一的,用户在创建后无法更改它。这将允许我在每次获取任何帖子或评论时都拥有 username 属性,而不是对显示的每个帖子或评论运行查询以使用 uid 获取用户名。但是,我最初选择将 uid 作为主键,因为它保存用户的 firebase id,保证是唯一的并且始终引用相同的对象。我不知道哪条路线最理想。
感谢您的宝贵时间:)
一个可能的解决方案可能是将
last_shown_post_id
属性存储在 users
表中。
然后从概念上(简化)您为用户获取帖子的请求将是:
SELECT posts.post_id FROM posts, post_tags
WHERE posts.post_id = post_tags.post_id
AND post_tags.tag_id IN {?}
AND posts.post_id > lastShownPostIdForYourUser
ORDER BY posts.post_id
LIMIT ?
收到新一批帖子后,您需要为用户更新
last_shown_post_id
。
UPDATE users
SET last_shown_post_id = newLastShownPostId
WHERE uid = ?
附注如果您不想显示非常旧的帖子,您可以在第一个查询中添加日期条件。