Implementazione di commenti e Mi piace nel database


146

Sono uno sviluppatore di software. Adoro programmare, ma odio i database ... Attualmente sto creando un sito Web in cui un utente potrà contrassegnare un'entità come piaciuta (come in FB), contrassegnarla e commentarla .

Rimango bloccato nella progettazione di tabelle di database per gestire questa funzionalità. La soluzione è banale, se possiamo farlo solo per un tipo di cosa (es. Foto). Ma devo abilitarlo per 5 cose diverse (per ora, ma presumo anche che questo numero possa crescere, man mano che l'intero servizio cresce).

Ho trovato alcune domande simili qui, ma nessuna di esse ha una risposta soddisfacente, quindi sto ponendo di nuovo questa domanda.

La domanda è: come progettare correttamente, efficientemente ed elasticamente il database, in modo che possa memorizzare commenti per tabelle diverse , like per tabelle diverse e tag per loro. Alcuni modelli di design come risposta saranno i migliori;)

Descrizione dettagliata : ho una tabella User con alcuni dati utente e altre 3 tabelle : Photocon fotografie , Articlescon articoli , Placescon luoghi . Voglio abilitare qualsiasi utente registrato a:

  • commentare una di quelle 3 tabelle

  • contrassegnare uno di loro come piace

  • contrassegnare uno di essi con qualche tag

  • Voglio anche contare il numero di Mi piace per ogni elemento e il numero di volte in cui quel particolare tag è stato usato.

1 ° metodo :

a) Per i tag , creerò un tavolo Tag [TagId, tagName, tagCounter] , poi creerò molti-a-molti rapporti tabelle per: Photo_has_tags, Place_has_tag, Article_has_tag.

b) Lo stesso vale per i commenti.

c) Creerò un tavolo LikedPhotos [idUser, idPhoto] , LikedArticles[idUser, idArticle], LikedPlace [idUser, idPlace]. Il numero di Mi piace verrà calcolato dalle query (che, presumo sia negativo). E...

Davvero non mi piace questo disegno per l'ultima parte, ha un cattivo odore per me;)


2 ° approccio :

Creerò una tabella ElementType [idType, TypeName == some table name]che verrà popolata dall'amministratore (me) con i nomi delle tabelle che possono essere apprezzate , commentate o taggate . Quindi creerò tabelle :

a) LikedElement [idLike, idUser, idElementType, idLikedElement]e lo stesso per commenti e tag con le colonne appropriate per ciascuno. Ora, quando voglio fare una foto piaciuta inserirò:

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

e per i luoghi:

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

e così via ... Penso che il secondo approccio sia migliore, ma penso anche che manchi qualcosa in questo design ...

Alla fine, mi chiedo anche quale sia il posto migliore dove riporre un contatore per quante volte è stato apprezzato l'elemento. Mi vengono in mente solo due modi:

  1. nella Photo/Article/Placetabella element ( )
  2. selezionando count ().

Spero che la mia spiegazione del problema sia ora più approfondita.


Hai considerato XML?
CodyBugstein,

1
Raramente trovo domande come questa che sono al 100% quello che ho in mente, la tua domanda è incredibilmente completa! Grazie @Kokos.
aderchox,

Risposte:


195

La soluzione più estensibile è avere solo una tabella "base" (collegata a "Mi piace", tag e commenti) e "ereditare" tutte le altre tabelle da essa. L'aggiunta di un nuovo tipo di entità implica semplicemente l'aggiunta di una nuova tabella "ereditata", che si inserisce automaticamente in tutto il macchinario like / tag / comment.

Il termine entità-relazione per questo è "categoria" (consultare la Guida ai metodi ERwin , sezione: "Relazioni del sottotipo"). Il simbolo della categoria è:

Categoria

Supponendo che un utente possa apprezzare più entità, uno stesso tag può essere utilizzato per più di un'entità ma un commento è specifico dell'entità, il modello potrebbe essere simile al seguente:

Diagramma ER


A proposito, ci sono circa 3 modi per implementare la "categoria ER":

  • Tutti i tipi in una tabella.
  • Tutti i tipi di calcestruzzo in tabelle separate.
  • Tutti i tipi concreti e astratti in tabelle separate.

A meno che tu non abbia requisiti di prestazione molto severi, il terzo approccio è probabilmente il migliore (ovvero le tabelle fisiche corrispondono 1: 1 alle entità nel diagramma sopra).


2
ottima risposta, grazie. Spero, riuscirò a implementarlo ... e mi chiedo come Django ORM gestirà per mapparlo (o come lo farò da solo ... ma, questo è l'altro problema;)) Ma puoi spiegare io, perché penso di non capirlo bene - cosa hai disegnato per me (grazie!) è il terzo approccio che hai menzionato?
Kokos,

2
@Kokos Essenzialmente, l'approccio (3) significa che ENTITY è una tabella, PHOTO è una tabella, ARTICLE è una tabella e PLACE è una tabella. L'approccio (2) significherebbe che non esiste una tabella per ENTITY e l'approccio (1) significherebbe che esiste una sola tabella. L'esistenza di tutti questi approcci (tutti con i loro punti di forza e di debolezza) è la sfortunata conseguenza del fatto che un tipico RDBMS non supporta l'ereditarietà delle tabelle in modo nativo.
Branko Dimitrijevic,

1
+1 grazie per l'ottima spiegazione e riferimenti su "categorie". Avevo intenzione di pubblicare una domanda vicina a questa, ma hai risposto qui.
Andy Holaday,

2
@BrankoDimitrijevic Perché le entità tabelle non possono avere un proprio PK come PhotoID, ArticleID, ArticleID ecc. Ma hanno anche un'altra colonna per Entity_ID come FK? Non è necessario?
volume uno,

3
@Orion Il massimo per BIGINTè 9223372036854775807. Supponendo che si inserisca una riga al secondo, si esauriranno i valori disponibili in ~ 300 miliardi di anni. Sicuramente, a quel punto sarai in grado di eseguire il porting su interi a 128 bit!
Branko Dimitrijevic,

22

Dato che "odi" i database, perché stai cercando di implementarne uno? Invece, chiedi aiuto a qualcuno che ama e respira queste cose.

Altrimenti, impara ad amare il tuo database. Un database ben progettato semplifica la programmazione, la progettazione del sito e ne semplifica il funzionamento continuo. Anche un designer d / b esperto non avrà una previsione completa e perfetta: alcuni cambiamenti dello schema lungo la strada saranno necessari quando emergono modelli di utilizzo o cambiano i requisiti.

Se si tratta di un progetto individuale, programmare l'interfaccia del database in semplici operazioni usando le procedure memorizzate: add_user, update_user, add_comment, add_like, upload_photo, list_comments, ecc. Non incorporare lo schema in nemmeno una riga di codice. In questo modo, lo schema del database può essere modificato senza influenzare alcun codice: solo le procedure memorizzate dovrebbero conoscere lo schema.

Potrebbe essere necessario riformattare lo schema più volte. E 'normale. Non preoccuparti di renderlo perfetto la prima volta. Renderlo abbastanza funzionale da prototipare un progetto iniziale. Se hai il lusso del tempo, usalo un po ', quindi elimina lo schema e fallo di nuovo. È sempre meglio la seconda volta.


2
Perché devo implementarlo da solo. Almeno per ora ... e, ho pensato che forse è una buona occasione per iniziare a gradire un po 'i database;) Grazie per il tuo suggerimento con la procedura memorizzata. Qualcuno lo sa, se sono mappati automaticamente da Django ORM?
Kokos,

6
Adoro la tua ultima frase: è sempre meglio la seconda volta.
Lewis,

2
È sempre meglio la seconda volta. Yup
Gammer,

20

Questa è un'idea generale, per favore non prestare molta attenzione allo stile dei nomi dei campi, ma più alla relazione e alla struttura

inserisci qui la descrizione dell'immagine

Questo pseudocodice riceverà tutti i commenti della foto con ID 5
SELEZIONA * DA azioni
DOVE azioni.id_Stuff = 5
AND actions.typeStuff = "foto"
AND actions.typeAction = "comment"

Questo pseudocodice otterrà tutti i
Mi piace o gli utenti a cui è piaciuta la foto con ID 5 (puoi usare count () per ottenere solo la quantità di Mi piace)

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

Penso che ti potrebbero piacere anche i commenti, come, facendo clic su un link "mi piace" in un commento. Questa query otterrà un commento SELECT * FROM actions WHERE actions.id=133 AND actions.typeStuff = "comment" AND actions.typeAction = "like"
simile

1
Ricorderò sicuramente questa soluzione per ulteriori versioni del mio sistema :)
Kokos,

Ho 2 tabelle roba stuff1 e stuff2 ... Ho seguito questo diagramma ma c'è un errore sql durante l'utilizzo di questo ... stuff1, stuff2 sono due tabelle indipendenti con le loro chiavi primarie indipendenti e la tabella delle azioni ha una colonna id_stuff a cui fa riferimento queste due tabelle stuff1, stuff2. Ora per esempio stuff1 ha 5 righe, stuff2 ha 10 righe, quando provo ad aggiungere una riga nella tabella delle azioni con id_stuff niente meno di 5 diciamo '3' esegue la query perché esiste una riga con id_stuff '3' sia in stuff1 che in stuff2, ma se provo ad aggiungere una riga con id_stuff maggiore di 5 ... (continua al prossimo commento)
vikas devde

1
Se uno deve implementare i Mi piace in questo modo, rende più difficile avvisare l'utente dei nuovi Mi piace. Richiederebbe un altro tavolo.
Greg L

4
In che modo la id_stuffcolonna conterrà valori univoci in ciascuna delle tre tabelle?
volume uno,

0

per quanto ho capito. sono richiesti più tavoli. C'è una relazione da molte a molte tra loro.

  • Tabella che memorizza i dati dell'utente come nome, cognome, data di nascita con un campo identità.
  • Tabella che memorizza i tipi di dati. questi tipi possono essere foto, condivisioni, collegamenti. ogni tipo deve avere una tabella univoca. pertanto, esiste una relazione tra le loro singole tabelle e questa tabella.
  • ogni diverso tipo di dati ha la sua tabella. ad esempio aggiornamenti di stato, foto, collegamenti.
  • l'ultima tabella è per molte o molte relazioni che memorizzano un ID, un ID utente, un tipo di dati e un ID dati.

se pubblichi il diagramma del database. posso disegnare la relazione.
Erencan,

0

Guarda i modelli di accesso che ti serviranno. Qualcuno di loro sembra aver reso particolarmente difficile o inefficiente la mia scelta progettuale o l'altra?

In caso contrario favorire quello che richiede un minor numero di tabelle

In questo caso:

  1. Aggiungi commento: o scegli una particolare tabella molte / molte o inseriscila in una tabella comune con un identificatore specifico noto per ciò che piace, penso che il codice client sarà leggermente più semplice nel tuo secondo caso.
  2. Trova commenti per l'elemento: qui sembra che usare una tabella comune sia leggermente più semplice - abbiamo solo una singola query parametrizzata per tipo di entità
  3. Trova i commenti di una persona su un tipo di cosa: query semplice in entrambi i casi
  4. Trova tutti i commenti di una persona su tutte le cose: questo sembra poco nodoso in entrambi i modi.

Penso che il tuo approccio "discriminato", opzione 2, produca query più semplici in alcuni casi e non sembri molto peggio negli altri, quindi ci andrei.


0

Sicuramente vai con il secondo approccio in cui hai una tabella e memorizza il tipo di elemento per ogni riga, ti darà molta più flessibilità. Fondamentalmente, quando si può fare logicamente qualcosa con un minor numero di tabelle, è quasi sempre meglio scegliere un numero inferiore di tabelle. Un vantaggio che mi viene in mente in questo momento sul tuo caso particolare, considera che vuoi eliminare tutti gli elementi piaciuti di un determinato utente, con il tuo primo approccio devi emettere una query per ogni tipo di elemento ma con il secondo approccio può essere fatto con una sola query o considera quando vuoi aggiungere un nuovo tipo di elemento, con il primo approccio implica la creazione di una nuova tabella per ogni nuovo tipo ma con il secondo approccio non dovresti fare nulla ...


-1

Prendi in considerazione l'uso della tabella per entità per commenti ed ecc. Altre tabelle: migliore condivisione e ridimensionamento. Non è un problema controllare molte tabelle simili per tutti i framework che conosco.

Un giorno dovrai ottimizzare le letture da tale struttura. Puoi facilmente creare tabelle agragating su quelle di base e perdere un po 'sulle scritture.

Un grande tavolo con dizionario potrebbe diventare incontrollabile un giorno.


Più tabelle significa che sarà meno gestibile. I singoli tavoli possono essere suddivisi dalla maggior parte dei d / b.
Wallyk
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.