Дизайн базы данных: лучшая структура таблицы для захвата отношений между пользователем и другом? - PullRequest
31 голосов
/ 18 декабря 2008

Я пытаюсь разработать модель данных, которая обозначает, что один пользователь является другом другого пользователя. Это то, что я придумал до сих пор, но это кажется неуклюжим, есть ли лучшее решение?

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

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

Ответы [ 13 ]

53 голосов
/ 19 декабря 2008
UserRelationship
====
RelatingUserID
RelatedUserID
Type[friend, block, etc]

Согласитесь, что взаимность не является столбцом; нарушает нормализацию.

29 голосов
/ 11 июля 2015

Чтобы перейти одна запись на двух пользователей и избежать потребления дополнительной памяти, которую предлагают предлагаемые методы (вдвое больше, чем необходимо, поскольку для каждого пользователя имеется две записи), вы можете сделать следующее:

  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: один из пользователей удалил другого из своих друзей

Это решение эффективно с точки зрения памяти и скорости, поскольку вы создаете, храните и обновляете только одну запись.

8 голосов
/ 19 декабря 2008

В настоящее время я создаю сайт социальной сети для клиента, и я выразил это таким образом

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 для таблицы person. Я сохраняю список состояний в таблице FriendStatus, чтобы указать, был ли что-то запрошено, принято, отклонено, проигнорировано и т. Д. Поле Timestamp является стандартным в моем проекте для указания создания записи (это шаблонная вещь, используемая базовым классом постоянства). ) и его вид дублируется в этой таблице, поскольку Person1RequestTimestamp содержит те же данные. Я также фиксирую, когда Person2 увидел запрос и выполнил действие (которое указывается в FriendStatusId), и сохранил его в Person2AcknowledgeTimestamp).

В одном из основных предположений этого плана можно указать, что Person1 запрашивал дружбу с Person2 - если эта дружба принята, тогда дружба считается взаимной.

5 голосов
/ 18 декабря 2008

Я бы сделал что-то похожее на то, что у вас есть, но убрал бы флаг "IsMutual". Просто добавьте вторую строку с обратными значениями, когда она взаимна. Он добавляет строки, но чувствует себя намного чище.

2 голосов
/ 09 ноября 2011

Я сделал это так:

СТОЛ пользователя

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>';
}
2 голосов
/ 19 апреля 2011

Что вы думаете о моем решении?

У вас есть 3 стола

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

Вы входите в систему, проверяете, не нахожусь ли я в таблице друзей, если да, перечислите друзей (я в списке друзей> в списке друзей) (я в списке друзей> список друзей)

Есть ли у меня запрос? (Я в flaggedID?) Знаете его? Если нет, удалите запись; если да, создайте новую запись в запросе, поскольку меня поместили во флаггер, и флаггер вошел во флаг. Теперь у нас есть взаимная связь между двумя записями в таблице запросов, поэтому мы удаляем обе записи и помещаем их в таблицу друзей. Легко отделить req / friends.

2 голосов
/ 19 декабря 2008

Вероятно, слишком много, но можно смоделировать семантическую сеть. Можно использовать формат FOAF (FOAF Friend of a Friend).

2 голосов
/ 18 декабря 2008

Возможно, добавьте таблицу отношений, поместите туда свойства отношений и сделайте ссылку на нее из UserFriend.

1 голос
/ 03 апреля 2009

Вам действительно нужен физический стол, чтобы узнать, есть ли общие друзья? Почему бы не выполнить 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);

Результаты запроса должны возвращать всех общих друзей.

1 голос
/ 19 декабря 2008

Дружба менее очевидна, чем классические сценарии самостоятельного объединения работодателя / босса и пользователя / супруга. Дружба это отношения или деятельность? Я получил много критики за пренебрежение последним. В любом случае, вам, вероятно, понадобится более одной таблицы, независимо от того, насколько универсальна ваша модель данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...