39

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

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

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

14 回答 14

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

同意相互性不属于列;打破规范化。

于 2008-12-18T21:04:15.017 回答
57

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

  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
    

你有什么:

  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将检查此列的语句,反之亦然,这样更快。

示例场景

  1. no record: 没有关系

  2. pending_first_second: 第一个向第二个发了好友请求

  3. friends: 第二个批准了好友请求

  4. no record:其中一个用户从他的朋友中删除了另一个

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

于 2015-07-10T22:52:43.630 回答
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 字段是 person 表的 FK。我在 FriendStatus 表中保留了一个状态列表,用于涵盖是否已请求、接受、拒绝、忽略等。Timestamp 字段在我的设计中是标准的,用于指示记录创建(它是基本持久性类中使用的模式事物) 及其在此表中的重复类型,因为 Person1RequestTimestamp 包含相同的数据。我还捕获了 Person2 何时看到请求并对其执行操作(在 FriendStatusId 中指示)并将其存储在 Person2AcknowledgeTimestamp 中)。

此设计的核心假设之一可以说是 Person1 请求 Person2 的友谊——如果接受该友谊,则认为该友谊是相互的。

于 2008-12-18T21:21:18.117 回答
5

我会做与您所做的类似的事情,但删除“IsMutual”标志。当它是相互的时,只需添加具有反向值的第二行。它确实添加了行,但感觉更干净。

于 2008-12-18T20:58:22.360 回答
3

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

于 2008-12-18T20:57:55.590 回答
3

我是这样做的:

表用户

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

TABLE 好友关系

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>';
}
于 2011-11-09T10:35:27.590 回答
2

可能超出了顶部,但可以使用语义网络来对此进行建模。可以使用 FOAF(朋友的 FOAF 朋友)格式。

于 2008-12-18T21:16:25.303 回答
2

你觉得我的解决方案怎么样?

你有 3 张桌子

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

你登录,检查我是否在朋友表中,如果是,列出朋友(我在friender>listfriended)(我在friended>listfriender)

我有要求吗?(我在 flaggedID 中吗?)认识他吗?如果没有,删除记录;如果是,请在请求中创建新记录,因为我被放入标记器并且标记器被标记。现在我们在请求表中的 2 条记录之间具有相互关系,因此我们将两者都删除并将它们放入朋友表中。易于分离请求/朋友。

于 2011-04-18T23:04:40.640 回答
1

友谊没有经典的雇主/老板和用户/配偶自加入场景那么明确。友谊是一种关系还是一种活动?我因忽视后者而受到相当多的批评。无论哪种方式,无论您的数据模型多么通用,您都可能需要多个表。

于 2008-12-18T21:13:27.167 回答
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);

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

于 2009-04-03T18:40:20.367 回答
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

我也认为这种方法更“交易安全”。想象一下,您向某人发送好友请求,然后阻止该人。如果那个人后来接受了好友请求,那也没关系。它不会改变关系的状态,因为它们是完全独立的。

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

我宁愿在数据库级别处理这个问题。如果您有一群程序员在开发应用程序,那么很快就会有人在某个地方忘记这个问题并创建一个难以发现的错误。

于 2017-08-10T08:47:21.043 回答
0

据我了解,友谊是两个用户(用户 1 和用户 2)之间关系的结果,因为用户 1 可以有 0 个或多个用户作为朋友,反之亦然,用户 2,因此联结表“朋友”出现在中间表示这样的关系:

User1 id(int) 用户名​​(string)

User2 id(int) 用户名​​(string)

朋友 ---- id(int) user1_Id(int) user2_Id(int) active(bool)

user1_Id 和 user2_Id 都是 Frind 表中的 FK

我希望我是对的。

于 2018-06-26T14:23:10.327 回答
-1

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

1. user
u_id int
u_username string
balahhh............

2. 友谊
fs_id int related_id int
related_id
int

于 2014-02-07T04:54:02.960 回答
-2

我也在做一个类似的项目,你需要描述友谊,其中关于你自己和朋友的信息是从一张表中获取的

答:我创建了“友谊”表,我通过“friend_id”获取朋友的数据,以及他们认识的日期。为了链接它们,我使用了“关系”表。此链接的 ERD 图(数据库)的图像朋友关系

于 2020-11-02T12:05:40.130 回答