Wdrażanie komentarzy i polubień w bazie danych

Jestem programistą. Uwielbiam kodować, ale nienawidzę baz danych... Obecnie tworzę stronę, na której użytkownik będzie mógł oznaczyć podmiot jako liked (Jak na FB), tag it i comment .

Utknąłem na projektowaniu tabel baz danych do obsługi tej funkcjonalności. Rozwiązanie jest banalne, jeśli możemy to zrobić tylko dla jednego rodzaju rzeczy (np. zdjęcia). Ale muszę włączyć to dla 5 różnych rzeczy (na razie, ale zakładam również, że ta liczba może rosnąć, wraz z rozwojem całego serwisu).

Znalazłem tutaj podobne pytania, ale żadne z nich nie ma satysfakcjonującej odpowiedzi, więc zadaję to pytanie ponownie.

Pytanie brzmi, jak prawidłowo, efektywnie i elastycznie zaprojektować bazę danych, aby mogła przechowywać komentarze dla różnych tabel , Polubienia dla różnych tabel i znaczników dla nich. Jakiś wzór projektowy jako odpowiedź będzie najlepszy ;)

Szczegółowy opis : I have a table User z pewnymi danymi użytkownika i 3 więcej tabel : Photo z fotografiami, Articles z artykułami, Places z miejscami . Chcę umożliwić każdemu zalogowanemu użytkownikowi:

  • Skomentuj dowolny z tych 3 tabel

  • Zaznacz dowolne z nich jako lubiane

  • Oznacz każdy z nich jakimś tagiem

  • Chcę również policzyć liczbę Polubienia dla każdego elementu i liczbę razy, kiedy dany tag został użyty.

1St podejście :

A) Dla znaczników, stworzę tabelę Tag [TagId, tagName, tagCounter], Następnie stworzę wiele do wielu relacje tabele dla: Photo_has_tags, Place_has_tag, Article_has_tag.

B) to samo liczy się dla komentarzy.

C) stworzę tabelę LikedPhotos [idUser, idPhoto], LikedArticles[idUser, idArticle], LikedPlace [idUser, idPlace]. Liczba polubień będzie obliczane przez queries (co, zakładam, że jest złe). I...

Naprawdę nie podoba mi się ten projekt na ostatnią część, źle dla mnie pachnie;)


2nd podejście :

Stworzę tabelę ElementType [idType, TypeName == some table name], która będzie wypełniona przez administratora (mnie) nazwami tabel które mogą być , skomentował lub otagował. Następnie stworzę tabele :

A) LikedElement [idLike, idUser, idElementType, idLikedElement] i to samo dla Komentarze i Tagi z odpowiednimi kolumnami dla każdego. Teraz, gdy chcę zrobić zdjęcie lubiane wstawię:

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

I dla miejsc:

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

I tak dalej... Myślę, że drugie podejście jest lepsze, ale też czuję, że czegoś brakuje również w tym projekcie...

W końcu zastanawiam się również, które miejsce najlepiej przechowywać licznik, ile razy element był lubiany. Mogę myśleć tylko na dwa sposoby:

  1. in element (Photo/Article/Place) table
  2. by select count ().

Mam nadzieję, że moje wyjaśnienie problemu jest teraz bardziej dokładne.

Author: Angel Politis, 2011-11-13

7 answers

Najbardziej rozszerzalnym rozwiązaniem jest posiadanie tylko jednej" podstawowej "tabeli (połączonej z "Polubienia", tagami i komentarzami) i "dziedziczenie" z niej wszystkich innych tabel. Dodanie nowego rodzaju encji polega na dodaniu nowej "odziedziczonej" tabeli - następnie automatycznie podłącza się do całej maszyny like/tag / comment.

Entity-relationship termin dla tego jest "kategoria" (patrz ERwin Methods Guide , sekcja: "Subtyp Relationships"). Symbol kategorii to:

Kategoria

Zakładając użytkownik może polubić wiele encji, ten sam tag może być używany dla więcej niż jednego encji, ale komentarz jest specyficzny dla encji, twój model może wyglądać tak:

Na


BTW, są w przybliżeniu 3 sposoby implementacji "kategorii ER":

  • Wszystkie typy w jednej tabeli.
  • wszystkie rodzaje betonu w osobnych tabelach.
  • wszystkie konkretne i abstrakcyjne typy w oddzielnych tabelach.

Jeśli nie masz bardzo rygorystycznych wymagań dotyczących wydajności, trzecie podejście jest chyba najlepszy (co oznacza, że tabele fizyczne pasują 1:1 do Bytów na powyższym diagramie).

 145
Author: Branko Dimitrijevic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-13 18:04:59

Skoro "nienawidzisz" baz danych, dlaczego próbujesz je wdrożyć? Zamiast tego poproś o pomoc kogoś, kto kocha i oddycha tymi rzeczami.

W Przeciwnym Razie, naucz się kochać swoją bazę danych. Dobrze zaprojektowana baza danych upraszcza programowanie, inżynierię witryny i usprawnia jej dalsze działanie. Nawet doświadczony projektant d / b nie będzie miał kompletnego i doskonałego foresight: niektóre zmiany schematu w dół drogi będą potrzebne w miarę pojawiania się wzorców użytkowania lub zmiany wymagań.

Jeśli jest to jednoosobowy projekt, program interfejsu bazy danych do prostych operacji za pomocą procedur składowanych: add_user, update_user, add_comment, add_like, upload_photo, list_comments, itp. Nie osadzaj schematu nawet w jednym wierszu kodu. W ten sposób schemat bazy danych może zostać zmieniony bez wpływu na żaden kod: tylko procedury składowane powinny wiedzieć o schemacie.

Może być konieczne kilkukrotne przeformułowanie schematu. To normalne. Nie martw się o to, aby był idealny pierwszy raz. Po prostu spraw, by był wystarczająco funkcjonalny, aby prototypować początkowy projekt. Jeśli masz luksus czasu, użyj go trochę, a następnie usunąć schemat i zrobić to ponownie. Jest Zawsze lepiej za drugim razem.

 17
Author: wallyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-13 16:21:00

To jest ogólna idea nie zwracaj uwagi na stylizację nazw pól, ale bardziej na relację i strukturę

Tutaj wpisz opis obrazka

Ten pseudokod otrzyma wszystkie komentarze zdjęcia o ID 5
SELECT * FROM actions
WHERE actions. id_Stuff = 5
I działania.typeStuff= "photo"
I działania.typeAction = "comment"

Ten pseudokod dostanie wszystkich lubiących lub użytkowników, którzy lubili zdjęcie o ID 5
(możesz użyć count() aby po prostu uzyskać ilość polubień)

SELECT * FROM actions  
WHERE actions.id_Stuff = 5  
AND actions.typeStuff="photo"  
AND actions.typeAction = "like"  
 16
Author: user964260,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-15 03:25:51

O ile rozumiem. wymagane jest kilka tabel. Istnieje wiele relacji między nimi.

  • tabela, która przechowuje dane użytkownika, takie jak imię, nazwisko, data urodzenia z polem tożsamości.
  • Tabela przechowująca typy danych. te typy mogą być Zdjęcia, akcje, linki. każdy typ musi mieć unikalną tabelę. w związku z tym istnieje zależność między ich poszczególnymi tabelami a tą tabelą.
  • każdy inny typ danych ma swoją tabelę. na przykład aktualizacje statusu, zdjęcia, linki.
  • Ostatnia tabela jest dla relacji wielu do wielu przechowujących id, user id, typ danych i data id.
 0
Author: erencan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-13 16:22:51

Spójrz na wzorce dostępu, których będziesz potrzebować. Czy któraś z nich wydaje się być szczególnie trudna lub nieefektywna?

Jeśli nie preferujesz tego, który wymaga mniejszej liczby tabel

W Tym Przypadku:

  1. Dodaj komentarz: albo wybierasz konkretną tabelę many/many, albo wstawiasz do wspólnej tabeli o znanym identyfikatorze dla tego, co jest lubiane, myślę, że kod klienta będzie nieco prostszy w twoim drugim przypadku.
  2. Znajdź komentarze do item: tutaj wydaje się, że używanie wspólnej tabeli jest nieco łatwiejsze - mamy tylko jedno zapytanie parametryzowane przez typ encji
  3. Znajdź komentarze osoby na temat jednego rodzaju rzeczy: proste zapytanie w obu przypadkach
  4. Znajdź wszystkie komentarze osoby na temat wszystkich rzeczy: to wydaje się trochę szorstkie tak czy inaczej.

Myślę, że Twoje "dyskryminowane" podejście, opcja 2, daje prostsze zapytania w niektórych przypadkach, a w innych nie wydaje się dużo gorsze, więc poszedłbym z tym.

 0
Author: djna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-13 16:34:17

Zdecydowanie skorzystaj z drugiego podejścia, w którym masz jedną tabelę i przechowujesz Typ elementu dla każdego wiersza, co da ci o wiele większą elastyczność. Zasadniczo, gdy coś można logicznie zrobić z mniejszą liczbą stołów, prawie zawsze lepiej jest przejść z mniejszą liczbą stołów. Jedną z zalet, która przychodzi mi teraz na myśl w twoim konkretnym przypadku, weź pod uwagę, że chcesz usunąć wszystkie lubiane elementy pewnego użytkownika, przy pierwszym podejściu musisz wydać jedno zapytanie dla każdego typu elementu, ale z drugie podejście można to zrobić tylko jednym zapytaniem lub rozważyć, gdy chcesz dodać nowy Typ elementu, przy pierwszym podejściu polega to na tworzeniu nowej tabeli dla każdego nowego typu, ale przy drugim podejściu nie powinno się nic robić...

 0
Author: nobody,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-13 17:20:03

Rozważ użycie tabeli dla każdego podmiotu w komentarzach itp. Więcej tabel - lepsze odłamywanie i skalowanie. Nie jest problemem kontrolowanie wielu podobnych tabel dla wszystkich frameworków, które znam.

Pewnego dnia będziesz musiał zoptymalizować odczyty z takiej struktury. Możesz łatwo tworzyć tabele agragacyjne nad bazowymi i tracić trochę na zapisach.

Jeden duży stół ze słownikiem może pewnego dnia stać się niekontrolowany.

 -1
Author: Oroboros102,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-13 17:01:41