English 中文(简体)
如何为实现好友关系建立数据库表格的模型?
原标题:
  • 时间:2008-12-18 20:55:24
  •  标签:
Closed. This question is opinion-based. It is not currently accepting answers.

想要改进这个问题吗?通过编辑此帖子更新问题,使其可以用事实和引用作为答案。

Closed 2 years ago.

This post was edited and submitted for review 14 days ago and failed to reopen the post:

原关闭原因未解决。

我正在尝试设计一个数据模型,用于表示一个用户是另一个用户的朋友。这是我目前想出来的,但它似乎很笨重,有更好的解决方案吗?

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

UserFriend
===========
UserId
FriendId
IsMutual
IsBlocked
最佳回答
UserRelationship
====
RelatingUserID
RelatedUserID
Type[friend, block, etc]

同意互惠关系不适合作为一列; 违反规范化。

问题回答

为了每两个用户只有一个记录,避免使用额外的内存,可以采用以下方法:

  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. 最有趣的部分- 类型: 对于一个关系的所有可能状态,您都可以创建相应的值。例如:

    pending_first_second
    pending_second_first
    friends
    block_first_second
    block_second_first
    block_both
    

你有什么:

  1. The user_first_id < user_second_id ensures that there is only one record of a relationship between two given users, since this and primary key constraints won t allow placing it otherwise.
  2. By proper switching between the relationship states, you determine how each of two users relate to each other. If there is no relationship between two users, there is no record.
  3. 为了找出两个用户之间的关系(以及更新),你只需使用一个查询:

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

    没有一个语句来检查这些列相反的情况,这样会更快。

示例情景

  1. 无记录:未处于关系中

  2. pending_first_second:第一方向第二方发出了好友请求。

  3. 朋友:第二个通过了好友请求

  4. 无记录:其中一位用户将另一位用户从朋友列表中删除了。

这个解决方案在内存和速度方面都非常高效,因为您只创建、存储和更新了单个记录。

我目前正在为客户建造一个社交网络网站,我是这样表达的。

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
);

每个人都被存储在个人表中(想象一下)。Person1Id和Person2Id字段是对个人表的外键。我在FriendStatus表中维护一个状态列表,用于覆盖是否请求、接受、拒绝、忽略等。时间戳字段在我的设计中是标准的,用于指示记录创建(它是基本持久性类中使用的一种模式),在这个表中它有点重复,因为Person1RequestTimestamp包含相同的数据。我还捕捉了Person2何时看到请求并采取行动(在FriendStatusId中指示),并将其存储在Person2AcknowledgeTimestamp中。

这个设计的一个核心假设是,Person1 请求与 Person2 友谊 - 如果这个友谊被接受了,那么这个友谊就被认为是相互的。

我会做类似于您的事情,但是移除“IsMutual”标识。当它是共同的时,只需添加一个具有相反值的第二行即可。这确实会增加行数,但感觉更清晰。

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

我是这样做的:

用户表

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> ;
}

可能有点过头,但可以使用语义网络来进行建模。可以使用FOAF(FOAF Friend of a Friend)格式。

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

你有三张桌子。

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

您登录后检查我是否在好友表中,如果是,则列出好友(如果我在发送请求的人是好友,则列出被请求人)(如果我被请求为好友,则列出发送请求的人)。

Do I have request? (Am I in flaggedID?) Know him? If not, delete record; if yes, create new record in request as me get putted in flagger and the flagger get in flagged. Now we have mutuality between 2 records in request table so we delete both and put them in friend table. Easy to separate req/friends.

友谊关系不像经典的雇佣者/老板和用户/配偶自连接场景那样清晰明确。友谊是一种关系还是一种活动?因为没有注意到后者,所以我受到了相当多的批评。无论如何,您可能需要超过一个表,无论您的数据模型多么通用。

你真的需要一个物理桌子来发现是否有共同的朋友吗?为什么不做一个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);

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

嗯,我来晚了,但这是我的出价。

首先是桌子:

User
-id

Type
-id

Relationship
-user_id_1
-user_id_2
-type_id

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

friend
ignored

这使添加新的类型很容易。我不需要考虑或创建所有类型的所有可能组合。我只需添加新类型即可。

建立友谊,需要在关系表中输入两个条目。如果两个用户都同意他们是朋友,他们就是朋友。如果只有一个人说他与另一个人是朋友,而另一个人将他拦截,他们就不是朋友。

进行查询非常简单。这里是如何在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

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

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

我更喜欢在数据库层面上处理这个问题。如果你有一群程序员在应用程序上工作,不久之后就会有人在某个地方忘记了这个问题,导致产生难以找到的错误。

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

用户1 ID(整数)用户名(字符串)

用户2 ID(整型) 用户名(字符串)

Friend ---- id(int) user1_Id(int) user2_Id(int) active(bool)

user1_Id和user2_Id都是Friend表中的外键。

我希望我是对的。

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

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

2. friendship
fs_id int
relating_id int
related_id int





相关问题
热门标签