Come progettare una tabella del database delle relazioni per archiviare le relazioni di amicizia?


9

Voglio progettare un tavolo per archiviare le relazioni di amicizia nel mio progetto web

Dovrebbe soddisfare almeno le seguenti 4 condizioni:

che invia la richiesta di aggiunta amico, ad es. (se A TO B, questa colonna sarà A)

che ricevono la richiesta di aggiunta di un amico, ad esempio (se A TO B questa colonna sarà B)

lo stato attuale, ad es. (0 indica rifiutato mentre 1 indica accettato o 2 indica non elaborato

la nostra relazione amica è bilaterale

Se qualcuno di voi ha esperienza con questo, qualsiasi suggerimento è il benvenuto

il mio disegno attuale (penso male adesso) è come questo sono le colonne

frienshipId  
fromUserId  
toUserId  
status  
requestTime

Posso suggerire di usare la vista del codice (evidenziare il testo e premere ctrl-k o mettere quattro spazi prima di ogni riga) ed evidenziare il tuo DDL in modo che possiamo vedere come è progettato il tuo modello di dati (o come vuoi progettarlo)
jcolebrand

Controlla anche la discussione qui: stackoverflow.com/questions/10807900/…
Flo

Utilizzare un database grafico. Questi sono progettati proprio per queste circostanze.
Michael Green,

Risposte:


9

Creerei un tavolo molto simile a quello che hai tu. Sto usando i tipi di dati e la sintassi di SQL Server, potrebbe essere necessario modificare a seconda della piattaforma.

CREATE TABLE FriendStatus
(FriendStatusId BIGINT PRIMARY KEY IDENTITY(1,1),
FromUserId BIGINT,
ToUserId BIGINT,
StatusId TINYINT,
SentTime DATETIME2,
ResponseTime DATETIME2);

L'indicizzazione della tabella sarà fondamentale man mano che la tabella cresce fino a decine e centinaia di milioni.


Che dire di un indice cluster / chiave primaria su StatusId?
bernd_k l'

Risolto il problema con il nome duplicato. L'indice cluster dovrebbe essere su FriendStatusId. La chiave primaria potrebbe essere FriendStatusId o una combinazione di FromUserId e ToUserId.
mrdenny l'

Tuttavia, se consenti richieste di amicizia multiple, vorrai il PK su FromUserID, ToUserId, SentTime o Clustered Index.
mrdenny l'

la tua strategia di denominazione è migliore ...
Ciao 福气 鱼

8

Su PostgreSQL:

CREATE TABLE users (
    users_id serial PRIMARY KEY,
    name text UNIQUE NOT NULL
);

CREATE TABLE friends (
    friends_id serial PRIMARY KEY,
    timestamp TIMESTAMPTZ default now(),
    user_a integer NOT NULL REFERENCES users,
    user_b integer NOT NULL REFERENCES users,
    status integer NOT NULL default 2
)

Per elencare le amicizie, una vista:

CREATE VIEW friendships AS
    SELECT DISTINCT user_a, user_b FROM friends WHERE status = 1
    UNION
    SELECT DISTINCT user_b, user_a FROM friends WHERE status = 1;

Puoi usarlo così:

INSERT INTO users ( name ) VALUES ( 'foo' );
INSERT INTO users ( name ) VALUES ( 'bar' );
INSERT INTO users ( name ) VALUES ( 'baz' );

SELECT * FROM users;
 users_id | name 
----------+------
        1 | foo
        2 | bar
        3 | baz

INSERT INTO FRIENDS ( user_a, user_b, status ) VALUES ( 1, 2, 1 );
INSERT INTO FRIENDS ( user_a, user_b, status ) VALUES ( 2, 1, 1 );
INSERT INTO FRIENDS ( user_a, user_b, status ) VALUES ( 1, 3, 1 );

SELECT * FROM friendships ORDER BY user_a, user_b;
 user_a | user_b 
--------+--------
      1 |      2
      1 |      3
      2 |      1
      3 |      1

SELECT a.name, b.name
    FROM friendships
    JOIN users a ON a.users_id = user_a
    JOIN users b ON b.users_id = user_b
    ORDER BY a.name, b.name;
 name | name 
------+------
 bar  | foo
 baz  | foo
 foo  | bar
 foo  | baz

3

Cosa ti fa pensare che il tuo design attuale sia cattivo? Ecco una tabella di creazione per Oracle:

CREATE TABLE IVR.FRIEND (
     FRIENDID   NUMBER(7) NOT NULL 
   , FROMUSERID NUMBER(7) NOT NULL 
   , TOUSERID   NUMBER(7) NOT NULL 
   , STATUSID   NUMBER(2) NOT NULL
   , REQUESTED  DATE      NOT NULL 
   , CONSTRAINT FRIEND_PK PRIMARY KEY (FRIENDID) ENABLE 
);
CREATE SEQUENCE FRIENDIDSEQ;

Se il database è Oracle, potresti prendere in considerazione una colonna virtuale indicizzata che limiterà i dati alle voci necessarie per particolari query. Ad esempio, potresti avere una colonna virtuale chiamata AcceptedFromUserId che utilizza la funzione DECODE (StatusId, 1, FromUserId, NULL). L'indice conterrebbe solo AcceptedUserIds e sarebbe quindi più piccolo di un indice per tutti gli UserId. Se si puliscono regolarmente le richieste rifiutate, una colonna virtuale indicizzata su PendingToUserId potrebbe essere più utile.

Un'alternativa se si avesse il partizionamento sarebbe quella di partizionare la tabella su StatusId.

Se non sono necessarie più richieste di amicizia tra gli stessi utenti contemporaneamente, è possibile abbandonare FriendId utilizzando FromUserId, ToUserId e StatusId come chiave primaria. In questo caso dovresti anche considerare di trasformare la tabella in una tabella organizzata dall'indice.


-2

Schema:

CREATE TABLE users (
    users_id serial PRIMARY KEY,
    name text UNIQUE NOT NULL
);

CREATE TABLE friends (
    friends_id serial PRIMARY KEY,
    timestamp TIMESTAMPTZ default now(),
    user_a integer NOT NULL REFERENCES users,
    user_b integer NOT NULL REFERENCES users,
    status integer NOT NULL default 2
)

Da PHP:

select * 
from friends 
where user_a=$myid or user_b=$myid

E cosa fare con la reciprocità? (E la friendsdefinizione della tabella è sospetta di errore di sintassi.)
dezso
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.