数据库设计:捕获用户/朋友关系的最佳表结构?

时间:2008-12-18 20:55:24

标签: database-design social-networking

我正在尝试设计一个数据模型,表示一个用户是另一个用户的朋友。这是我到目前为止所提出的,但看起来很笨重,是否有更好的解决方案?

User
=====
Id
Name
etc...

UserFriend
===========
UserId
FriendId
IsMutual
IsBlocked

14 个答案:

答案 0 :(得分:53)

UserRelationship
====
RelatingUserID
RelatedUserID
Type[friend, block, etc]

同意共同不属于专栏;打破正常化。

答案 1 :(得分:29)

每两个用户一个记录,并避免消耗建议方法建议的额外内存(需要两倍,因为每个用户有两条记录),您可以执行以下操作:

  1. 表格结构:

    USER_RELATIONSHIP {
        user_first_id,
        user_second_id,
        type
    
        primary key(user_first_id, user_second_id)
    }
    
  2. 确保:user_first_id < user_second_id

  3. 最有趣的部分 - type:对于关系的所有可能状态,您可以创建相应的值。例如:

    pending_first_second
    pending_second_first
    friends
    block_first_second
    block_second_first
    block_both
    
  4. 你有什么:

    1. user_first_id < user_second_id确保只有一个 记录两个给定用户之间的关系,因为这和主键约束 不允许另外放置。
    2. 通过在关系状态之间进行适当切换,可以确定两个用户中的每个用户如何相互关联。如果两个用户之间没有关系,则没有记录。
    3. 要找出两个用户之间的关系(以及更新),您只需查看一个查询:

      select * from USER_RELATIONSHIP where
          user_first_id = user1_id and
          user_second_id = user2_id;
      

      没有or语句可以检查此列,反之亦然,这更快。

    4. 示例方案

      1. no record:不在关系中

      2. pending_first_second:第一个向第二个

      3. 发出了朋友请求
      4. friends:第二个批准了好友请求

      5. no record:其中一位用户将其他用户从他的朋友中删除

      6. 此解决方案在内存和速度方面都很有效,因为您只创建,存储和更新一条记录。

答案 2 :(得分:8)

我目前正在为客户建立一个社交网站,我用这种方式表达了

CREATE TABLE [dbo].[PersonFriend] (
    [Id]                          INT            IDENTITY (1, 1) NOT NULL,
    [Timestamp]                   DATETIME       NOT NULL,
    [ChangeUser]                  NVARCHAR (200) NOT NULL,
    [FriendStatusId]              TINYINT        NOT NULL,
    [Person1Id]                   INT            NOT NULL,
    [Person2Id]                   INT            NOT NULL,
    [Person1RequestTimestamp]     DATETIME       NOT NULL,
    [Person2AcknowledgeTimestamp] DATETIME       NULL
);

每个人都存储在Person表中(想象一下)。 Person1Id和Person2Id字段是人员表的FK。我在FriendStatus表中保留了一个状态列表,用于覆盖是否已经请求,接受,拒绝,忽略等。时间戳字段在我的设计中是标准的,用于表示记录创建(它是基本持久化类使用的模式事物)由于Person1RequestTimestamp包含相同的数据,因此它在此表中的重复类型。当Person2看到请求并在其上发出一个动作(在FriendStatusId中显示)并将其存储在Person2AcknowledgeTimestamp中时,我也会捕获。

这种设计的核心假设之一可以说是Person1要求Person2的友谊 - 如果这种友谊被接受,那么友谊被认为是相互的。

答案 3 :(得分:5)

我会做类似于你所拥有的东西,但删除“IsMutual”标志。当它是相互的时,只需添加具有反向值的第二行。它确实添加了行,但感觉更清洁。

答案 4 :(得分:2)

也许添加一个Relationship表,将关系属性放在那里,然后从UserFriend引用它。

答案 5 :(得分:2)

可能在顶部,但可以使用语义网来模拟这个。可以使用FOAF(FOAF朋友的朋友)格式。

答案 6 :(得分:2)

您如何看待我的解决方案?

你有3张桌子

1 **the user** (id,.etc)
2 **friend_request**(id,flaggerID,flaggedID)
3 **friend**(id,frienderID,friendedID)

你登录,检查我是否在朋友表中,如果是列出朋友(我在friender&gt; list friended)(我在friended&gt; listfriender)

我有要求吗? (我在flaggedID吗?)认识他?如果没有,删除记录;如果是,请在请求中创建新记录,因为我在旗手中被推入并且旗手被标记。现在我们在请求表中有2个记录之间的相互关系,所以我们删除它们并将它们放在朋友表中。 易于分离req / friends。

答案 7 :(得分:2)

我是这样做的:

TABLE用户

id  name
-----------
1   foo
2   roo
3   shoo
4   mooo

表朋友关系

id   u_id f_id
--------------
1    1    2
2    2    1
3    3    1
4    1    3

每次朋友请求都接受插入反向方式1 2 & 2 1和简单查询:

$ufq=mysql_query("SELECT t1.f_id,t2.id,t2.name FROM friends AS t1, user AS t2 WHERE t1.u_id='$u_id' AND t2.id=t1.f_id ORDER BY t2.name ")or die(mysql_error());
while($fn=mysql_fetch_array($ufq)){
    echo $fn["name"].'<br>';
}

答案 8 :(得分:1)

与传统的雇主/老板和用户/配偶自我加入方案相比,友谊不那么明确。友谊是一种关系还是一种活动?由于忽视了后者,我收到了相当多的批评。无论哪种方式,无论数据模型的通用程度如何,您可能都需要多个表。

答案 9 :(得分:1)

你真的需要一张物理桌来发现是否有共同的朋友?为什么不进行如下的SQL查询:

SELECT U.ID, U.NAME FROM USER U
INNER JOIN USERFRIEND UF
ON U.ID = UF.FRIENDID
WHERE U.ID = (SELECT USER.ID FROM USER
            WHERE USER.ID = friend_id AND USER.ID != your_id);

查询的结果应该返回所有共同的朋友。

答案 10 :(得分:0)

我认为你应该创建两个表:

用户
       u_id int
       u_username字符串
       balahhh ............

2.友谊        fs_id int
       related_id int
       related_id int

答案 11 :(得分:0)

好吧,我已经迟到了,但这是我的出价。

首先是表格:

User
-id

Type
-id

Relationship
-user_id_1
-user_id_2
-type_id

现在,我想保持我的类型表简单。因此,我添加的类型仅代表单个用户与另一个用户的关系。它们永远不代表双向关系。例如:

friend
ignored

这使得添加新类型变得容易。我不必考虑或创建所有类型的所有可能组合。我只是添加新类型。

要设置友谊,您需要在关系表中输入2个条目。如果两个用户都认为他们是朋友,那么他们就是朋友。如果只有一个人说他是另一个人的朋友,而另一个人阻止他,那么他们就不是朋友。

进行查询非常简单。以下是您如何获得MySQL中的所有朋友:

SELECT u.* FROM user u
LEFT JOIN relationship r1 ON u.id = r1.user_id_2
LEFT JOIN relationship r2 ON u.id = r2.user_id_1
WHERE r1.user_id_1 = <my_user_id> # my relationship with them
AND r1.type_id = <friend_type_id> # i say i'm a friend
AND r2.user_id_2 = <my_user_id> # their relationship with me
AND r2.type_id = <friend_type_id> # they say they're friends

我也认为这种方法更加安全,交易安全&#34;。想象一下,您向某人发送了一个朋友请求,然后阻止该人。如果那个人以后接受了朋友请求,那就不重要了。它并没有改变关系的状态,因为它们是完全独立的。

如果你有一个代表双向关系的单一类型,你将被迫在你的代码中进行某种评估,一旦朋友接受了朋友的请求,关系的新状态究竟应该是什么。如果您不这样做,您最终可能会取消阻止用户并让该用户与他或她已阻止的用户成为朋友。

我宁愿在数据库级别处理这个问题。如果你有一群程序员正在处理这个应用程序,那么在某人忘记这个问题并且创建了一个难以发现的bug之前,它不会花很长时间。

答案 12 :(得分:0)

根据我的理解,友谊是两个用户(User1和User2)之间的关系的结果,并且由于user1可以将0个或多个用户作为朋友,反之亦然,因此user2是连接表中间的“朋友”来表示这种关系:

  

User1 id(int)用户名(string)

     

User2 id(int)用户名(string)

     

朋友   ---- id(int)user1_Id(int)user2_Id(int)活动(布尔)

user1_Id和user2_Id都是Frind表中的FK

我希望我是对的。

答案 13 :(得分:-1)

我还在做一个类似的项目,您需要描述友谊, 其中有关您自己和朋友的信息是从一张桌子上获得的。

答案: 我创建了“友谊”表,在该表中,我通过“ friend_id”获取了朋友的数据以及他们见面的那天。为了链接它们,我使用了“关系”表。通过此链接Friend relation

生成的ERD图(数据库)的图像