Implementación de comentarios y me gusta en la base de datos

146

Soy un desarrollador de software. Me encanta codificar, pero odio las bases de datos ... Actualmente, estoy creando un sitio web en el que un usuario podrá marcar una entidad como me gusta (como en FB), etiquetarla y comentar .

Me atasco en el diseño de tablas de bases de datos para manejar esta funcionalidad. La solución es trivial, si podemos hacer esto solo para un tipo de cosas (por ejemplo, fotos). Pero necesito habilitar esto para 5 cosas diferentes (por ahora, pero también asumo que este número puede crecer, a medida que crece todo el servicio).

Encontré algunas preguntas similares aquí, pero ninguna de ellas tiene una respuesta satisfactoria, por lo que estoy haciendo esta pregunta nuevamente.

La pregunta es cómo diseñar la base de datos de manera adecuada, eficiente y elástica , de modo que pueda almacenar comentarios para diferentes tablas , me gusta para diferentes tablas y etiquetas para ellos. Algún patrón de diseño como respuesta será mejor;)

Descripción detallada : Tengo una tabla User con algunos datos de usuario, y 3 tablas más : Photocon fotografías , Articlescon artículos , Placescon lugares . Quiero habilitar a cualquier usuario registrado para:

  • comentar cualquiera de esas 3 tablas

  • marcar cualquiera de ellos como gustado

  • etiquetar cualquiera de ellos con alguna etiqueta

  • También quiero contar la cantidad de Me gusta para cada elemento y la cantidad de veces que se usó esa etiqueta en particular.

1 st enfoque :

a) Para las etiquetas , voy a crear una tabla Tag [TagId, tagName, tagCounter] , a continuación, voy a crear muchos-a-muchos relaciones mesas para: Photo_has_tags, Place_has_tag, Article_has_tag.

b) Lo mismo cuenta para los comentarios.

c) Voy a crear una tabla LikedPhotos [idUser, idPhoto] , LikedArticles[idUser, idArticle], LikedPlace [idUser, idPlace]. El número de Me gusta se calculará mediante consultas (lo cual, supongo que es malo). Y...

Realmente no me gusta este diseño para la última parte, me huele mal;)


2 nd enfoque :

Crearé una tabla ElementType [idType, TypeName == some table name]que será rellenada por el administrador (yo) con los nombres de las tablas que pueden gustarse , comentarse o etiquetarse . Entonces crearé tablas :

a) LikedElement [idLike, idUser, idElementType, idLikedElement]y lo mismo para Comentarios y Etiquetas con las columnas apropiadas para cada uno. Ahora, cuando quiera hacer una foto que me guste, insertaré:

typeId = SELECT id FROM ElementType WHERE TypeName == 'Photo'
INSERT (user id, typeId, photoId)

y para lugares:

typeId = SELECT id FROM ElementType WHERE TypeName == 'Place'
INSERT (user id, typeId, placeId)

y así sucesivamente ... Creo que el segundo enfoque es mejor, pero también siento que falta algo en este diseño también ...

Por último, también me pregunto cuál es el mejor lugar para almacenar el mostrador por cuántas veces le gustó el elemento. Solo puedo pensar en dos formas:

  1. en la Photo/Article/Placetabla element ( )
  2. por cuenta selecta ().

Espero que mi explicación del problema sea más exhaustiva ahora.

Kokos
fuente
¿Has considerado XML?
CodyBugstein
1
Raramente encuentro preguntas como esta que son 100% de lo que tengo en mente, ¡tu pregunta es increíblemente completa! Gracias @Kokos.
aderchox

Respuestas:

195

La solución más extensible es tener una sola tabla "base" (conectada a "me gusta", etiquetas y comentarios) y "heredar" todas las demás tablas de ella. Agregar un nuevo tipo de entidad implica simplemente agregar una nueva tabla "heredada"; luego se conecta automáticamente a toda la maquinaria de me gusta / etiqueta / comentario.

El término entidad-relación para esto es "categoría" (consulte la Guía de métodos de ERwin , sección: "Relaciones de subtipo"). El símbolo de categoría es:

Categoría

Suponiendo que a un usuario le gusten varias entidades, se puede usar una misma etiqueta para más de una entidad pero un comentario es específico de la entidad, su modelo podría verse así:

Diagrama ER


Por cierto, hay aproximadamente 3 formas de implementar la "categoría ER":

  • Todos los tipos en una tabla.
  • Todos los tipos de hormigón en mesas separadas.
  • Todos los tipos concretos y abstractos en tablas separadas.

A menos que tenga requisitos de rendimiento muy estrictos, el tercer enfoque es probablemente el mejor (lo que significa que las tablas físicas coinciden 1: 1 con las entidades en el diagrama anterior).

Branko Dimitrijevic
fuente
2
Gran respuesta, gracias. Espero que logre implementarlo ... y me pregunto cómo manejará Django ORM para mapearlo (o cómo lo haré yo solo ... pero, ese es el otro problema;)) Pero, ¿pueden explicarlo? yo, porque creo que no lo entiendo correctamente: lo que has dibujado para mí (¡gracias!) es el tercer enfoque que mencionaste.
Kokos
2
@Kokos Esencialmente, el enfoque (3) significa que ENTITY es una tabla, PHOTO es una tabla, ARTICLE es una tabla y PLACE es una tabla. El enfoque (2) significaría que no hay una tabla para ENTITY y el enfoque (1) significaría que solo hay una tabla. La existencia de todos estos enfoques (todos con sus fortalezas y debilidades) es la desafortunada consecuencia del hecho de que un RDBMS típico no admite la herencia de tablas de forma nativa.
Branko Dimitrijevic
1
+1 gracias por la gran explicación y referencias sobre "categorías". Iba a publicar una pregunta cerca de esto, pero la respondiste aquí.
Andy holaday
2
@BrankoDimitrijevic ¿Por qué las tablas de entidades Photo, Article, Place no pueden tener su propia PK, por ejemplo, PhotoID, ArticleID, etc., pero también tienen otra columna para Entity_ID como FK? ¿Es esto innecesario?
volumen uno
3
@Orion El máximo para BIGINT9223372036854775807. Suponiendo que inserte una fila cada segundo, se quedará sin valores disponibles en ~ 300 mil millones de años. ¡Seguramente, para entonces, podrá transferir a enteros de 128 bits!
Branko Dimitrijevic
22

Ya que "odias" las bases de datos, ¿por qué estás tratando de implementar una? En cambio, solicite ayuda de alguien que ama y respira estas cosas.

De lo contrario, aprende a amar tu base de datos. Una base de datos bien diseñada simplifica la programación, diseña el sitio y suaviza su operación continua. Incluso un diseñador experimentado de d / b no tendrá una previsión completa y perfecta: se necesitarán algunos cambios de esquema en el futuro a medida que surjan patrones de uso o cambien los requisitos.

Si se trata de un proyecto individual, programe la interfaz de la base de datos en operaciones simples utilizando procedimientos almacenados: add_user, update_user, add_comment, add_like, upload_photo, list_comments, etc. No incruste el esquema en una sola línea de código. De esta manera, el esquema de la base de datos se puede cambiar sin afectar ningún código: solo los procedimientos almacenados deben conocer el esquema.

Puede que tenga que refactorizar el esquema varias veces. Esto es normal. No te preocupes por hacerlo perfecto la primera vez. Simplemente hágalo lo suficientemente funcional como para crear un prototipo de diseño inicial. Si tiene el lujo del tiempo, úselo y luego elimine el esquema y vuelva a hacerlo. Siempre es mejor la segunda vez.

wallyk
fuente
2
Porque necesito implementarlo por mí mismo. Al menos por ahora ... y pensé que tal vez sea una buena ocasión para comenzar a gustar un poco las bases de datos;) Gracias por su sugerencia con el procedimiento almacenado. ¿Alguien sabe si Django ORM los asigna automáticamente?
Kokos
66
Me encanta tu última oración. Siempre es mejor la segunda vez.
Lewis
2
Siempre es mejor la segunda vez. Sí
Gammer
20

Esta es una idea general, no preste mucha atención al estilo de los nombres de campo, sino más a la relación y estructura

ingrese la descripción de la imagen aquí

Este pseudocódigo obtendrá todos los comentarios de la foto con ID 5
SELECT * FROM actions
WHERE actions.id_Stuff = 5
AND actions.typeStuff = "photo"
AND actions.typeAction = "comment"

Este pseudocódigo obtendrá todos los me gusta o usuarios a quienes les gustó la foto con ID 5
(puede usar count () para obtener la cantidad de me gusta)

SELECT * FROM actions  
WHERE actions.id_Stuff = 5  
AND actions.typeStuff="photo"  
AND actions.typeAction = "like"  
usuario964260
fuente
Creo que incluso te pueden gustar los comentarios, ya que, al hacer clic en un enlace "me gusta" en un comentario. Esta consulta obtendrá los gustos de un comentario (acción) con ID 133: SELECT * FROM actions WHERE actions.id=133 AND actions.typeStuff = "comment" AND actions.typeAction = "like"
user964260
1
Definitivamente recordaré esta solución para futuros lanzamientos de mi sistema :)
Kokos
Tengo 2 tablas de cosas stuff1 y stuff2 ... Seguí este diagrama pero hay un error sql al usar esto ... stuff1, stuff2 son dos tablas independientes con sus claves primarias independientes, y la tabla de acciones tiene una columna id_stuff que hace referencia a estos dos tabels stuff1, stuff2. Ahora, por ejemplo, stuff1 tiene 5 filas, stuff2 tiene 10 filas, cuando trato de agregar una fila en la tabla de acciones con id_stuff menos de 5, digamos '3', ejecuta la consulta porque existe una fila con id_stuff '3' en ambas cosas1 y stuff2, pero si intento agregar una fila con id_stuff mayor que 5 ... (continúe con el siguiente comentario)
vikas devde
1
Si uno quiere implementar Me gusta de esta manera, hace que la notificación al usuario de los nuevos Me gusta sea más difícil. Requeriría otra mesa.
Greg L
44
¿Cómo contendrá la id_stuffcolumna valores únicos en cada una de las tres tablas?
Volumen uno
0

hasta donde yo entiendo. Se requieren varias mesas. Hay una relación de muchos a muchos entre ellos.

  • Tabla que almacena los datos del usuario, como nombre, apellido, fecha de nacimiento con un campo de identidad.
  • Tabla que almacena los tipos de datos. Estos tipos pueden ser fotos, acciones, enlaces. cada tipo debe tener una tabla única. por lo tanto, existe una relación entre sus tablas individuales y esta tabla.
  • cada tipo de datos diferente tiene su tabla. por ejemplo, actualizaciones de estado, fotos, enlaces.
  • la última tabla es para una relación de muchos a muchos que almacena una identificación, identificación de usuario, tipo de datos e identificación de datos.
Erencan
fuente
si publica su diagrama de base de datos. Puedo dibujar la relación.
Erencan
0

Mira los patrones de acceso que vas a necesitar. ¿Alguno de ellos parece hacer particularmente difícil o ineficiente mi elección de diseño u otra?

Si no favorece el que requiere menos tablas

En este caso:

  1. Agregue comentario: puede elegir una tabla muchos / muchos en particular o insertarla en una tabla común con un identificador específico conocido de lo que le gusta, creo que el código del cliente será un poco más simple en su segundo caso.
  2. Buscar comentarios para el elemento: aquí parece que usar una tabla común es un poco más fácil: solo tenemos una única consulta parametrizada por tipo de entidad
  3. Encuentre comentarios de una persona sobre un tipo de cosa: consulta simple en cualquier caso
  4. Encuentre todos los comentarios de una persona sobre todas las cosas: esto parece un poco retorcido de cualquier manera.

Creo que su enfoque "discriminado", opción 2, produce consultas más simples en algunos casos y no parece mucho peor en los demás, por lo que seguiría con eso.

djna
fuente
0

Definitivamente vaya con el segundo enfoque donde tiene una tabla y almacene el tipo de elemento para cada fila, le dará mucha más flexibilidad. Básicamente, cuando algo se puede hacer lógicamente con menos tablas, casi siempre es mejor ir con menos tablas. Una ventaja que me viene a la mente ahora sobre su caso particular, considere que desea eliminar todos los elementos que le gustan a un determinado usuario, con su primer enfoque, debe emitir una consulta para cada tipo de elemento, pero con el segundo enfoque puede hacerse con solo una consulta o considerar cuándo desea agregar un nuevo tipo de elemento, con el primer enfoque implica crear una nueva tabla para cada nuevo tipo, pero con el segundo enfoque no debe hacer nada ...

nadie
fuente
-1

Considere usar la tabla por entidad para comentarios, etc. Más tablas: mejor fragmentación y escalado. No es un problema controlar muchas tablas similares para todos los marcos que conozco.

Algún día necesitarás optimizar las lecturas de dicha estructura. Puede crear fácilmente tablas agravantes sobre las básicas y perder un poco en las escrituras.

Una mesa grande con diccionario puede volverse incontrolable algún día.

Oroboros102
fuente
Más tablas significa que será menos mantenible. Las tablas individuales pueden dividirse en la mayoría de los d / bs.
wallyk