Implémentation des commentaires et des mentions J'aime dans la base de données


146

Je suis un développeur de logiciels. J'adore coder, mais je déteste les bases de données ... Actuellement, je crée un site Web sur lequel un utilisateur sera autorisé à marquer une entité comme aimée (comme dans FB), à la taguer et à la commenter .

Je reste bloqué sur la conception des tables de base de données pour gérer cette fonctionnalité. La solution est triviale, si nous ne pouvons le faire que pour un seul type de chose (par exemple, des photos). Mais je dois l'activer pour 5 choses différentes (pour le moment, mais je suppose également que ce nombre peut augmenter à mesure que l'ensemble du service se développe).

J'ai trouvé des questions similaires ici, mais aucune d'entre elles n'a de réponse satisfaisante, alors je pose à nouveau cette question.

La question est de savoir comment concevoir correctement, efficacement et élastiquement la base de données, afin qu'elle puisse stocker des commentaires pour différentes tables , des likes pour différentes tables et des balises pour elles. Un modèle de conception comme réponse sera le meilleur;)

Description détaillée : J'ai un tableau User avec quelques données utilisateur, et 3 autres tableaux : Photoavec des photos , Articlesavec des articles , Placesavec des lieux . Je souhaite permettre à tout utilisateur connecté de:

  • commenter l'un de ces 3 tableaux

  • marquer l'un d'entre eux comme aimé

  • taguer l'un d'eux avec un tag

  • Je veux également compter le nombre de likes pour chaque élément et le nombre de fois que cette balise particulière a été utilisée.

1 er approche :

a) Pour les étiquettes , je vais créer un tableau Tag [TagId, tagName, tagCounter] , je vais créer beaucoup à plusieurs relations tables pour: Photo_has_tags, Place_has_tag, Article_has_tag.

b) La même chose vaut pour les commentaires.

c) Je vais créer un tableau LikedPhotos [idUser, idPhoto] , LikedArticles[idUser, idArticle], LikedPlace [idUser, idPlace]. Le nombre de likes sera calculé par des requêtes (ce qui, je suppose, est mauvais). Et...

Je n'aime vraiment pas ce design pour la dernière partie, ça sent mauvais pour moi;)


2 ème approche :

Je vais créer une table ElementType [idType, TypeName == some table name]qui sera remplie par l'administrateur (moi) avec les noms des tables qui peuvent être aimées , commentées ou étiquetées . Ensuite, je créerai des tableaux :

a) LikedElement [idLike, idUser, idElementType, idLikedElement]et la même chose pour les commentaires et les balises avec les colonnes appropriées pour chacun. Maintenant, quand je veux faire une photo aimée, je vais insérer:

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

et pour les lieux:

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

et ainsi de suite ... Je pense que la deuxième approche est meilleure, mais j'ai aussi l'impression que quelque chose manque également dans cette conception ...

Enfin, je me demande aussi quel est le meilleur endroit pour stocker le comptoir pour combien de fois l'élément a été aimé. Je ne peux penser qu'à deux façons:

  1. dans la Photo/Article/Placetable element ( )
  2. en sélectionnant count ().

J'espère que mon explication de la question est maintenant plus approfondie.


Avez-vous envisagé XML?
CodyBugstein

1
Je trouve rarement des questions comme celle-ci qui sont à 100% ce que j'ai en tête, votre question est incroyablement complète! Merci @Kokos.
aderchox

Réponses:


195

La solution la plus extensible est de n'avoir qu'une seule table "de base" (connectée aux "likes", balises et commentaires), et en "hériter" toutes les autres tables. Ajouter un nouveau type d'entité implique simplement d'ajouter une nouvelle table "héritée" - elle se connecte alors automatiquement à l'ensemble de la machine like / tag / comment.

Le terme entité-relation pour cela est "catégorie" (voir le Guide des méthodes ERwin , section: "Relations de sous-types"). Le symbole de catégorie est:

Catégorie

En supposant qu'un utilisateur peut aimer plusieurs entités, une même balise peut être utilisée pour plus d'une entité mais un commentaire est spécifique à l'entité, votre modèle pourrait ressembler à ceci:

Diagramme ER


BTW, il existe environ 3 façons d'implémenter la "catégorie ER":

  • Tous les types dans une table.
  • Tous les types de béton dans des tableaux séparés.
  • Tous les types concrets et abstraits dans des tableaux séparés.

À moins que vous n'ayez des exigences de performances très strictes, la troisième approche est probablement la meilleure (ce qui signifie que les tables physiques correspondent 1: 1 aux entités du diagramme ci-dessus).


2
excellente réponse, merci. J'espère que je parviendrai à l'implémenter ... et je me demande comment Django ORM va gérer pour le mapper (ou comment je vais le faire moi-même ... mais, c'est l'autre problème;)) Mais, pouvez-vous expliquer moi, parce que je pense que je ne comprends pas bien - ce que vous avez dessiné pour moi (merci!) est la troisième approche que vous avez mentionnée?
Kokos

2
@Kokos Essentiellement, l'approche (3) signifie que ENTITY est une table, PHOTO est une table, ARTICLE est une table et PLACE est une table. L'approche (2) signifierait qu'il n'y a pas de table pour ENTITY et l'approche (1) signifierait qu'il n'y a qu'une seule table. L'existence de toutes ces approches (toutes avec leurs forces et leurs faiblesses) est la conséquence malheureuse du fait qu'un SGBDR typique ne supporte pas nativement l'héritage de table.
Branko Dimitrijevic

1
+1 merci pour la grande explication et les références sur les «catégories». J'allais poster une question proche de ceci mais vous y avez répondu ici.
andy holaday

2
@BrankoDimitrijevic Pourquoi les tables d'entité Photo, Article, Lieu ne peuvent-elles pas avoir leur propre PK, par exemple PhotoID, ArticleID, etc., mais aussi avoir une autre colonne pour Entity_ID en tant que FK? Est-ce inutile?
volume un

3
@Orion Le maximum pour BIGINTest 9223372036854775807. En supposant que vous insérez une ligne chaque seconde, vous manquerez de valeurs disponibles dans environ 300 milliards d'années. Vous pourrez sûrement porter des entiers de 128 bits d'ici là!
Branko Dimitrijevic

22

Puisque vous «détestez» les bases de données, pourquoi essayez-vous d'en implémenter une? Au lieu de cela, demandez l'aide de quelqu'un qui aime et respire ce genre de choses.

Sinon, apprenez à aimer votre base de données. Une base de données bien conçue simplifie la programmation, l'ingénierie du site et facilite son fonctionnement continu. Même un concepteur d / b expérimenté n'aura pas une vision complète et parfaite: certains changements de schéma seront nécessaires à mesure que les modèles d'utilisation émergent ou que les exigences changent.

S'il s'agit d'un projet individuel, programmez l'interface de la base de données dans des opérations simples à l'aide de procédures stockées: add_user, update_user, add_comment, add_like, upload_photo, list_comments, etc. N'incorporez pas le schéma dans une seule ligne de code. De cette manière, le schéma de la base de données peut être modifié sans affecter aucun code: seules les procédures stockées doivent connaître le schéma.

Vous devrez peut-être refactoriser le schéma plusieurs fois. C'est normal. Ne vous inquiétez pas de le rendre parfait du premier coup. Rendez-le simplement suffisamment fonctionnel pour prototyper une conception initiale. Si vous avez le luxe du temps, utilisez-le un peu, puis supprimez le schéma et recommencez. C'est toujours mieux la deuxième fois.


2
Parce que je dois le mettre en œuvre moi-même. Au moins pour le moment ... et j'ai pensé que c'était peut-être une bonne occasion de commencer à aimer un peu les bases de données;) Merci pour votre suggestion de procédure stockée. Quelqu'un sait-il s'ils sont automatiquement mappés par Django ORM?
Kokos

6
J'adore ta dernière phrase - C'est toujours mieux la deuxième fois.
Lewis

2
C'est toujours mieux la deuxième fois. Yup
Gammer

20

Ceci est une idée générale, veuillez ne pas prêter beaucoup d'attention au style des noms de champs, mais plus à la relation et à la structure

entrez la description de l'image ici

Ce pseudocode obtiendra tous les commentaires de photo avec l'ID 5
SELECT * FROM actions
WHERE actions.id_Stuff = 5
AND actions.typeStuff = "photo"
AND actions.typeAction = "comment"

Ce pseudocode obtiendra tous les goûts ou utilisateurs qui ont aimé la photo avec l'ID 5
(vous pouvez utiliser count () pour obtenir simplement le nombre de likes)

SELECT * FROM actions  
WHERE actions.id_Stuff = 5  
AND actions.typeStuff="photo"  
AND actions.typeAction = "like"  

Je pense que vous pouvez même aimer les commentaires, comme en cliquant sur un lien "J'aime" dans un commentaire. Cette requête obtiendra les goûts d'un commentaire (action) avec l'ID 133: SELECT * FROM actions WHERE actions.id=133 AND actions.typeStuff = "comment" AND actions.typeAction = "like"
user964260

1
Je me souviendrai certainement de cette solution pour les versions ultérieures de mon système :)
Kokos

J'ai 2 tables de trucs stuff1 et stuff2 ... J'ai suivi ce diagramme mais il y a une erreur sql lors de l'utilisation de ceci ... stuff1, stuff2 sont deux tables indépendantes avec leurs clés primaires indépendantes, et la table d'action a une colonne id_stuff qui fait référence à ces deux tabels stuff1, stuff2. Maintenant, par exemple, stuff1 a 5 lignes, stuff2 a 10 lignes, quand j'essaie d'ajouter une ligne dans la table d'action avec id_stuff tout ce qui est inférieur à 5, disons '3', il exécute la requête car il existe une ligne avec id_stuff '3' dans les deux stuff1 et stuff2, mais si j'essaie d'ajouter une ligne avec id_stuff supérieur à 5 ... (continuer au commentaire suivant)
vikas devde

1
Si l'on doit implémenter les likes de cette manière, cela rend plus difficile la notification à l'utilisateur des nouveaux likes. Il faudrait une autre table.
Greg L

4
Comment la id_stuffcolonne contiendra-t-elle des valeurs uniques dans chacune des trois tables?
volume un

0

pour autant que je sache. plusieurs tables sont nécessaires. Il existe une relation plusieurs à plusieurs entre eux.

  • Table qui stocke les données utilisateur telles que le nom, le prénom, la date de naissance avec un champ d'identité.
  • Table qui stocke les types de données. ces types peuvent être des photos, des partages, des liens. chaque type doit avoir une table unique. par conséquent, il existe une relation entre leurs tables individuelles et cette table.
  • chaque type de données différent a sa table. par exemple, des mises à jour de statut, des photos, des liens.
  • la dernière table est pour plusieurs à plusieurs relations stockant un identifiant, un identifiant d'utilisateur, un type de données et un identifiant de données.

si vous publiez votre diagramme de base de données. je peux dessiner la relation.
erencan

0

Regardez les modèles d'accès dont vous aurez besoin. L'un d'entre eux semble-t-il avoir rendu particulièrement difficile ou inefficace mon choix de conception ou l'autre?

Sinon privilégiez celui qui nécessite le moins de tables

Dans ce cas:

  1. Ajouter un commentaire: vous choisissez une table plusieurs / plusieurs particulière ou insérez dans une table commune avec un identifiant spécifique connu pour ce qui est aimé, je pense que le code client sera légèrement plus simple dans votre deuxième cas.
  2. Rechercher des commentaires pour l'élément: ici, il semble que l'utilisation d'une table commune soit un peu plus facile - nous n'avons qu'une seule requête paramétrée par type d'entité
  3. Rechercher les commentaires d'une personne sur un type de chose: une simple requête dans les deux cas
  4. Trouvez tous les commentaires d'une personne sur toutes choses: cela semble peu gnarly de toute façon.

Je pense que votre approche «discriminée», option 2, donne des requêtes plus simples dans certains cas et ne semble pas beaucoup plus mauvaise dans les autres, alors je l'accepterais.


0

Allez certainement avec la deuxième approche où vous avez une table et stockez le type d'élément pour chaque ligne, cela vous donnera beaucoup plus de flexibilité. Fondamentalement, quand quelque chose peut logiquement être fait avec moins de tables, il est presque toujours préférable d'utiliser moins de tables. Un avantage qui me vient à l'esprit en ce moment à propos de votre cas particulier, considérez que vous souhaitez supprimer tous les éléments appréciés d'un certain utilisateur, avec votre première approche, vous devez émettre une requête pour chaque type d'élément, mais avec la deuxième approche, cela peut être fait avec une seule requête ou considérez quand vous voulez ajouter un nouveau type d'élément, avec la première approche, cela implique de créer une nouvelle table pour chaque nouveau type mais avec la deuxième approche, vous ne devriez rien faire ...


-1

Pensez à utiliser une table par entité pour les commentaires, etc. Plus de tables - meilleur partitionnement et mise à l'échelle. Ce n'est pas un problème de contrôler de nombreuses tables similaires pour tous les frameworks que je connais.

Un jour, vous devrez optimiser les lectures à partir d'une telle structure. Vous pouvez facilement créer des tables agragantes par rapport à celles de base et perdre un peu en écriture.

Une grande table avec dictionnaire peut devenir un jour incontrôlable.


Plus de tableaux signifie qu'il sera moins maintenable. Les tableaux individuels peuvent être fragmentés par la plupart des d / bs.
wallyk
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.