我应该如何设计用户拦截系统?

cco*_*der 1 postgresql database-design

我创建了一个小社交网站,其中包含用户生成的内容。如果用户不喜欢自己发布的内容,他们应该可以选择阻止对方。

所以我使用 postgresql 并且有三个简单的表。

Table User
id (pk)  | user_name
1       | a
2       | b
3       | c

Table Post
id (pk)  | user_id (fk)
1       | 1
2       | 3
3       | 2
4       | 2

Table Block
id (pk) | blocker_id (fk)  | blocked_id (fk)
1       | 1              | 2
2       | 2              | 1
Run Code Online (Sandbox Code Playgroud)

顺便说一句,正如您所看到的,我使用双向阻止,因为我不希望如果 user1 阻止 user2,则 user2 也不应该看到 user1 的帖子。

我写了一个sql:

SELECT * FROM Post p INNER JOIN Block b
ON p.user_id = b.blocker_id
WHERE b.blocked_id <> @current_user_id
Run Code Online (Sandbox Code Playgroud)

但是如果用户没有阻止任何人怎么办?此 SQL 不涵盖这种情况,它仅显示在表上有记录的用户帖子。

我的期望:

  • 对于 user1,此 sql 应返回 user3 和 user1 的帖子。
  • 对于 user2,它应该返回 user3 和 user2 的帖子。
  • 对于 user3,它应该返回每个用户的帖子。

我怎样才能做到这一点?

谢谢。

Laj*_*pad 6

首先,我认为你使阻塞对称的想法是错误的。想象一下当 user1 阻止 user2 时的情况,这会在您的情况下在两个方向上创建两个块。如果 user1 决定取消阻止 user2 怎么办?在这种情况下,您将需要删除两条记录。但是,如果他们都想互相阻止怎么办?在这种情况下,您也会有两条记录。因此解锁变得矛盾。我的建议是当 user1 阻止 user2 时创建一条记录并搜索 blocker_id 和Blocked_id,因此检查谁看不到谁的帖子将如下所示:

select *
from User
join Block
on User.id = Block.blocker_id or User.id = Block.blocked_id
Run Code Online (Sandbox Code Playgroud)

现在,让我们看看您的查询。不需要加入Block,而是需要检查是否存在Block记录:

select *
from Post p
where p.user_id = @current_user_id and
      not exists (select id
                  from Block
                  where Block.blocker_id = p.user_id or Block.blocked_id = p.user_id)
Run Code Online (Sandbox Code Playgroud)

请注意,我对 PostgreSQL 的工作不多(但一般来说对 SQL 的工作很多),所以如果我有一些语法错误,那么这可以归因于我对 PostgreSQL 的不懂。

编辑

解决方案是下面的代码:

select *
from Post p
where
not exists (select id
from Block
where ((Block.blocked_id = p.user_id) and (Block.blocker_id = @current_user_id)) or ((Block.blocked_id = @current_user_id) and (Block.blocker_id = p.user_id))
Run Code Online (Sandbox Code Playgroud)

说明:我们需要查找当前用户阻止作者或作者阻止当前用户的阻止记录。