it-swarm.com.de

Datenbankdesign: Beste Tabellenstruktur für die Erfassung der Beziehung zwischen Benutzer und Freund

Ich versuche, ein Datenmodell zu entwerfen, das einen Benutzer als Freund eines anderen Benutzers bezeichnet. Dies ist, was ich bis jetzt hatte, aber es scheint klobig, gibt es eine bessere Lösung?

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

UserFriend
===========
UserId
FriendId
IsMutual
IsBlocked
30
Zachary Yates
UserRelationship
====
RelatingUserID
RelatedUserID
Type[friend, block, etc]

Stimmen Sie zu, dass Gegenseitigkeit nicht als Kolonne gehört. bricht die Normalisierung.

52
chaos

Um einen Datensatz pro zwei Benutzer zu vermeiden und den zusätzlichen Speicher zu vermeiden, den die vorgeschlagenen Methoden vorschlagen (doppelt so viel wie erforderlich, da für jeden Benutzer zwei Datensätze vorhanden sind), können Sie Folgendes tun:

  1. Tabellenstruktur:

    USER_RELATIONSHIP {
        user_first_id,
        user_second_id,
        type
    
        primary key(user_first_id, user_second_id)
    }
    
  2. Stellen Sie sicher: user_first_id < user_second_id

  3. Der interessanteste Teil - type: Für alle möglichen Zustände einer Beziehung legen Sie die entsprechenden Werte an. Zum Beispiel:

    pending_first_second
    pending_second_first
    friends
    block_first_second
    block_second_first
    block_both
    

Was du hast:

  1. Der user_first_id < user_second_id stellt sicher, dass es nur einen -Datensatz einer Beziehung zwischen zwei bestimmten Benutzern gibt, da dies und die Primärschlüsseleinschränkungen Das Platzieren ansonsten nicht zulassen.
  2. Durch das richtige Wechseln zwischen den Beziehungszuständen bestimmen Sie, wie sich zwei Benutzer miteinander verhalten. Wenn keine Beziehung zwischen zwei Benutzern besteht, ist kein Datensatz vorhanden.
  3. Um die Beziehung zwischen zwei Benutzern herauszufinden (sowie das Update), gehen Sie einfach durch eine einzige Abfrage:

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

    ohne eine or-Anweisung, die diese Spalten umgekehrt prüfen würde, was schneller ist.

Beispielszenario :

  1. no record: sind nicht in einer Beziehung

  2. pending_first_second: Der erste hat eine Freundschaftsanfrage an den zweiten gestellt

  3. friends: Die Sekunde hat die Freundschaftsanfrage genehmigt

  4. no record: Einer der Benutzer entfernte den anderen aus seinen Absichten

Diese Lösung ist sowohl hinsichtlich des Arbeitsspeichers als auch der Geschwindigkeit effizient, da Sie nur einen einzigen Datensatz erstellen, speichern und aktualisieren.

27
Artem Novikov

Ich baue gerade eine Social-Networking-Site für einen Kunden auf und drücke die Dinge so aus

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

Jede Person wird in der Personentabelle gespeichert (stellen Sie sich das vor). Die Felder Person1Id und Person2Id sind in der Personentabelle FK. Ich behalte in der FriendStatus-Tabelle eine Statusliste, in der beschrieben wird, ob etwas angefordert, akzeptiert, abgelehnt, ignoriert wurde usw. Das Feld "Zeitmarke" ist in meinem Design Standard, um die Datensatzerstellung anzuzeigen ) und ihre Art, die in dieser Tabelle enthalten ist, da Person1RequestTimestamp die gleichen Daten enthält. Ich fange auch ein, wenn die Person2 die Anfrage sah und eine Aktion (die in FriendStatusId angezeigt wird) darauf ausführt und diese im Person2AcknowledgeTimestamp speichert. 

Eine der Kernannahmen dieses Entwurfs lässt sich feststellen, dass Person1 die Freundschaft von Person2 anforderte - wenn diese Freundschaft akzeptiert wird, wird die Freundschaft als gegenseitig betrachtet.

8
keithwarren7

Ich würde etwas Ähnliches tun wie das, was Sie haben, aber das "IsMutual" -Flag entfernen. Fügen Sie einfach eine zweite Zeile mit inversen Werten hinzu, wenn sie wechselseitig ist. Es fügt Zeilen hinzu, fühlt sich aber viel sauberer an.

5
Jeffrey

Was denkst du über meine Lösung?

Sie haben 3 Tische

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

Du meldest dich an, prüfe ob ich in der Freundesliste bin, ob ja Freunde auflisten (ich bin in friender> liste befreundet) (ich bin in befreundeten> listfriender)

Habe ich eine Anfrage? (Bin ich in flaggedID?) Kennen Sie ihn? Wenn nicht, löschen Sie den Datensatz. Wenn ja, erstelle einen neuen Datensatz in der Anfrage, während ich in Flagger und der Flagger in Flag gesetzt werde. Jetzt haben wir Gegenseitigkeit zwischen zwei Datensätzen in der Anforderungstabelle, so dass wir beide löschen und sie in die Freundentabelle legen Leicht zu trennen, req/Freunde.

2
csigarena

Fügen Sie vielleicht eine Beziehungstabelle hinzu, fügen Sie die Beziehungseigenschaften dort ein und referenzieren Sie sie von UserFriend.

2
rjurney

Wahrscheinlich übertrieben, aber man kann das Semantic Web verwenden, um dies zu modellieren. Man kann das FOAF-Format (FOAF-Freund eines Freundes) verwenden. 

2
tuinstoel

Ich habe es so gemacht:

TABLE-Benutzer

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

TABLE Freund Beziehung

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

Jedes Mal, wenn eine Freundschaftsanfrage akzeptiert wurde, wird der umgekehrte Weg 1 2 & 2 1 und eine einfache Abfrage eingefügt:

$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
aaryadev

Benötigen Sie tatsächlich einen physischen Tisch, um herauszufinden, ob es gemeinsame Freunde gibt? Warum nicht eine SQL-Abfrage wie:

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

Die Ergebnisse der Abfrage sollten alle gemeinsamen Freunde zurückgeben.

1
ChampionChicken

Freundschaften sind weniger eindeutig als die klassischen Szenarien der Arbeitgeber/Chefs und der Benutzer/Ehepartner. Ist Freundschaft eine Beziehung oder eine Aktivität? Ich habe ziemlich viel Kritik erhalten, weil ich Letzteres vernachlässigt habe. In jedem Fall werden Sie wahrscheinlich mehr als eine Tabelle benötigen, unabhängig davon, wie allgemein Ihr Datenmodell ist.

1
acoustickitty

Nun, ich bin zu spät zur Party, aber hier ist mein Angebot.

Zuerst die Tische:

User
-id

Type
-id

Relationship
-user_id_1
-user_id_2
-type_id

Nun möchte ich meine Typentabelle einfach halten. Die von mir hinzugefügten Typen stellen also nur die Beziehung eines einzelnen Benutzers zu einem anderen dar. Sie repräsentieren niemals die bidirektionale Beziehung. Zum Beispiel:

friend
ignored

Dies macht das Hinzufügen neuer Typen einfach. Ich muss nicht alle möglichen Kombinationen aller meiner Typen überdenken oder erstellen. Ich füge nur den neuen Typ hinzu.

Um eine Freundschaft aufzubauen, benötigen Sie zwei Einträge in der Beziehungstabelle. Wenn beide Benutzer zustimmen, dass sie Freunde sind, sind sie Freunde. Wenn nur einer sagt, er sei mit dem anderen befreundet, und der andere hat ihn blockiert, sind sie keine Freunde.

Abfragen zu machen ist sehr einfach. So erhalten Sie alle Freunde in 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

Ich denke auch, dass dieser Ansatz "transaktionssicherer" ist. Stellen Sie sich vor, Sie senden eine Freundschaftsanfrage an jemanden und blockieren diese Person anschließend. Wenn diese Person die Freundschaftsanfrage später akzeptiert, ist das egal. Es ändert nicht den Zustand der Beziehung, da sie völlig unabhängig sind.

Wenn Sie stattdessen einen einzigen Typ hätten, der die bidirektionale Beziehung darstelle, müssten Sie in Ihrem Code eine Art Bewertung des tatsächlichen Status der Beziehung vornehmen, sobald der Freund die Freundschaftsanfrage angenommen hat. Wenn Sie dies nicht tun, können Sie die Blockierung eines Benutzers beenden und diese Person mit dem von ihm blockierten Benutzer anfreunden.

Ich würde das lieber auf Datenbankebene erledigen. Wenn mehrere Programmierer an der Anwendung arbeiten, dauert es nicht lange, bis jemand dieses Problem irgendwo vergisst und ein schwer zu findender Fehler erstellt wird.

0

Nach meinem Verständnis ist Freundschaft ein Ergebnis einer Beziehung zwischen zwei Benutzern (Benutzer1 und Benutzer2) und weil ein Benutzer1 0 oder viele Benutzer als Freund (e) und umgekehrt Benutzer2 haben kann, daher eine Verbindungstabelle "Freund" Kommt in die Mitte, um diese Beziehung wie folgt darzustellen:

Benutzer1-ID (int) Benutzername (Zeichenfolge)

Benutzer2-ID (int) Benutzername (Zeichenfolge)

Freund ---- id (int) user1_Id (int) user2_Id (int) aktiv (bool)

Sowohl user1_Id als auch user2_Id sind FKs in Frind Table

Ich hoffe ich habe recht.

0
Xris

Ich denke, Sie sollten zwei Tabellen erstellen:

1. Nutzer
u_id int
u_username Zeichenfolge
balahhh ............

2. Freundschaft
fs_id int
beziehungs_id int
related_id int

0
bountyhunter