diseño de base de datos: Mejor estructura de la tabla para la captura de la relación usuario / amigo?

StackOverflow https://stackoverflow.com/questions/379236

  •  22-08-2019
  •  | 
  •  

Pregunta

Estoy tratando de diseñar un modelo de datos que denota ser un usuario amigo de otro usuario. Esto es lo que he encontrado hasta el momento, pero parece torpe, ¿hay una solución mejor?

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

UserFriend
===========
UserId
FriendId
IsMutual
IsBlocked
¿Fue útil?

Solución

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

De acuerdo en que la reciprocidad no pertenece como una columna; se rompe la normalización.

Otros consejos

Para ir un registro por dos usuarios y evitar el consumo de memoria extra que los métodos propuestos sugieren (dos veces tanto como sea necesario, ya que hay dos registros para cada usuario), puede hacer lo siguiente:

  1. Estructura de la tabla:

    USER_RELATIONSHIP {
        user_first_id,
        user_second_id,
        type
    
        primary key(user_first_id, user_second_id)
    }
    
  2. asegurar: user_first_id < user_second_id

  3. La parte más interesante - type: todos los estados posibles de una relación, se crean los valores correspondientes. Para exmaple:

    pending_first_second
    pending_second_first
    friends
    block_first_second
    block_second_first
    block_both
    

Lo que tienes:

  1. El user_first_id < user_second_id asegura que sólo hay una registro de una relación entre dos usuarios dados, ya que esto y restricciones de clave principal no permitirá la colocación de otra manera.
  2. Por conmutación apropiada entre los estados de relación, a determinar cómo cada uno de los dos usuarios se relacionan entre sí. Si no existe una relación entre dos usuarios, no hay ningún registro.
  3. Para averiguar la relación entre dos usuarios (así como la actualización), sólo tiene que ir por una sola consulta:

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

    sin una declaración or que comprobar este columnas viceversa, lo que es más rápido.

Ejemplo escenario :

  1. no record: no están en una relación

  2. pending_first_second: la primera hizo una solicitud de amistad a la segunda

  3. friends: el segundo aprobado la solicitud de amistad

  4. no record: uno de los usuarios eliminan el otro de sus Firends

Esta solución es eficiente en términos de memoria y velocidad, ya que permite crear, almacenar y actualizar sólo un registro único.

Actualmente estoy construyendo un sitio de redes sociales para un cliente y le expresé cosas de esta manera

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

A cada persona se almacena en la tabla Persona (imaginar que). Los campos Person1Id y Person2Id son FK a la mesa persona. Tengo una lista de estado en la tabla FriendStatus para cubrir si algo se ha pedido, aceptado, negado, ignorado etc. El campo de marca de hora es estándar en mi diseño para indicar la creación del registro (que es una cosa patrón que se utiliza en la persistencia de base por clase ) y su tipo de duplicado de esta tabla como la Person1RequestTimestamp contiene los mismos datos. También capturo cuando el Person2 vio la solicitud y realiza una acción (que consigue indica en FriendStatusId) en él y tienda que en el Person2AcknowledgeTimestamp).

Uno de los supuestos básicos de este diseño se puede afirmar que Persona1 solicitó amistad de Person2 -. Si se acepta que la amistad entonces la amistad se considera mutua

Me gustaría hacer algo similar a lo que tiene, pero quitar la bandera "IsMutual". Basta con añadir una segunda fila con los valores inversos cuando es mutuo. Se le añade filas, pero se siente mucho más limpio.

Tal vez agregar una tabla de relación, poner las propiedades de relación allí, y hacer referencia a ella desde UserFriend.

Probablemente exagerado pero se puede utilizar la web semántica para modelar esto. Uno puede utilizar el FOAF (FOAF amigo de un amigo) -format.

Lo hice así:

usuario TABLE

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

TABLA relación amigo

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

solicitud de amigo Cada vez aceptado 1 2 & 2 1 forma de inserción inversa y consulta sencilla:

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

¿Qué opinas sobre mi solución?

Usted tiene 3 mesas

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

iniciar sesión, compruebe si estoy en amigo mesa, si es así la lista de amigos (estoy en Friender> lista friended) (estoy en> listfriender friended)

¿Tengo solicitud? (¿Estoy en flaggedID?) Lo conoce? Si no es así, eliminar el registro; Si es así, crear un nuevo registro en la solicitud como que consigue putt en banderines y la meto en flagger marcado. Ahora tenemos la reciprocidad entre los 2 registros en la tabla pedido, por lo que eliminamos los dos y los ponemos en la mesa amigo. Fáciles de separar req / amigos.

Las amistades son menos claros que el clásico empleador / patrón y el usuario / cónyuge autocombinación escenarios. Es una relación de amistad o una actividad? He recibido una buena cantidad de críticas por descuidar este último. De cualquier manera, usted está probablemente va a necesitar más de una tabla, no importa qué tan genérica que su modelo de datos es.

¿Usted realmente necesita una tabla física para descubrir si hay amigos en común? ¿Por qué no hacer una consulta SQL como:

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

Los resultados de la consulta debe devolver todos los amigos en común.

Creo que debe crear dos tipos de tabla:

1. usuario
       u_id int
       cadena u_username
       balahhh ............

2. amistad
       fs_id int
       relating_id int
       related_id int

Bueno, llego tarde a la fiesta, pero aquí está mi oferta.

Primero las tablas:

User
-id

Type
-id

Relationship
-user_id_1
-user_id_2
-type_id

Ahora, yo quiero mantener mi mesa de tipo simple. Por lo que los tipos que sólo se suman representan la relación de un solo usuario con otro. Ellos nunca representan la relación bidireccional. Por ejemplo:

friend
ignored

Esto hace que la adición de nuevos tipos fácil. No tengo que pensar o crear todas las combinaciones posibles de todos mis tipos. Acabo de añadir el nuevo tipo.

Para configurar una amistad, se necesitaría 2 entradas en la tabla de relación. Si los usuarios están de acuerdo en que son amigos, son amigos. Si sólo uno quien dice que es amigo de la otra, y el otro lo ha bloqueado, no son amigos.

consultas de decisiones es muy simple. Así es como se obtiene todos los amigos en 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

También creo que este enfoque es más "transacción segura". Imagínese que usted envíe una solicitud de amistad a alguien y luego bloquear a esa persona después. Si esa persona después aceptar la solicitud de amistad, no importa. No cambia el estado de la relación, ya que son completamente independientes.

Si en su lugar había un solo tipo que representa la relación bidireccional, que se vería obligado a hacer algún tipo de evaluación en su código, de qué es exactamente el nuevo estado de la relación debe ser, una vez que el amigo aceptó la solicitud de amistad. Si no lo hace, usted podría terminar desbloquear un usuario y hacer que los amigos persona con el usuario que él o ella había bloqueado.

Me gustaría mucho manejar esto en el nivel de base de datos. Si usted tiene un montón de programadores que trabajan en la aplicación que no toma mucho tiempo antes de que alguien se olvida de este problema en algún lugar y se crea un error difícil de encontrar.

A mi entender la amistad es el resultado de una relación entre dos usuarios (Usuario1 y Usuario2), y porque un usuario1 puede tener 0 o muchos de usuario (s) amigo (s) y usuario2 viceversa, por lo tanto, una tabla de unión "amigo" commes en el medio para representar a esa relación como ésta:

  

Identificación del Usuario 1 (Int) nombre de usuario (cadena)

     

Identificación del Usuario 2 (int) nombre de usuario (cadena)

     

amigo   ---- id (int) User1_ID (int) User2_ID (int) activo (bool)

Tanto User1_ID y User2_ID son FKs en Frind Tabla

Espero que estoy en lo cierto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top