To dobre pytanie, które ilustruje problemy z nadmiernym osadzaniem się i jak sobie z tym radzić.
Przykład:polubienia postów
Pozostańmy za przykładem użytkowników lubiących posty, który jest prostym przykładem. Pozostałe relacje musiałyby zostać odpowiednio potraktowane.
Masz całkowitą rację, że przechowywanie polubień w poście prędzej czy później doprowadzi do problemu, że bardzo popularne posty osiągną limit rozmiaru.
Więc poprawnie wróciłeś, aby utworzyć post_likes
kolekcja. Dlaczego nazywam to poprawnym? Ponieważ pasuje do Twoich przypadków użycia oraz wymagań funkcjonalnych i niefunkcjonalnych!
- Skaluje się w nieskończoność (no cóż, istnieje teoretyczna granica, ale jest olbrzymia)
- Jest łatwy w utrzymaniu (utwórz unikalny indeks na
post_id
iliked_user_id
) i użytkowania (znany jest zarówno użytkownik, jak i post, więc dodanie polubienia to zwykła wstawka lub, co bardziej prawdopodobne, upsert) - Możesz łatwo dowiedzieć się, którzy użytkownicy lubią który post i który post jest lubiany przez jakich użytkowników
Jednak rozszerzyłbym nieco kolekcję, aby zapobiec niepotrzebnym zapytaniom w niektórych przypadkach użycia, które są częste.
Załóżmy na razie, że nie można zmienić tytułów postów i nazw użytkowników. W takim przypadku bardziej sensowny może być poniższy model danych
{
_id: new ObjectId(),
"post_id": someValue,
"post_title": "Cool thing",
"liked_user_id": someUserId,
"user_name": "JoeCool"
}
Załóżmy teraz, że chcesz wyświetlić nazwę użytkownika wszystkich użytkowników, którzy polubili post. W powyższym modelu byłoby to pojedyncze, dość szybkie zapytanie:
db.post_likes.find(
{"postId":someValue},
{_id:0,user_name:1}
)
Mając przechowywane tylko identyfikatory, to dość typowe zadanie wymagałoby co najmniej dwóch zapytań i – biorąc pod uwagę ograniczenie, że post może mieć nieskończoną liczbę polubień – potencjalnie ogromnego zużycie pamięci (musisz przechowywać identyfikatory użytkowników w pamięci RAM).
To prawda, że prowadzi to do pewnej nadmiarowości, ale nawet gdy miliony ludzi lubią posty, mówimy tylko o kilku megabajtach stosunkowo taniej (i łatwej do skalowania) przestrzeni dyskowej przy jednoczesnym uzyskaniu dużej wydajności pod względem doświadczenia użytkownika.
Teraz nadchodzi rzecz:nawet jeśli nazwy użytkowników i tytuły postów mogą ulec zmianie, wystarczyło wykonać wielokrotną aktualizację:
db.post_likes.update(
{"post_id":someId},
{ $set:{ "post_title":newTitle} },
{ multi: true}
)
Handlujesz, że trochę czasu zajmuje zrobienie dość rzadkich rzeczy, takich jak zmiana nazwy użytkownika lub posta w celu uzyskania ekstremalnej prędkości w przypadkach użycia, które zdarzają się niezwykle często.
Dolna linia
Należy pamiętać, że MongoDB jest bazą danych zorientowaną na dokumenty. Dlatego udokumentuj interesujące Cię zdarzenia wartościami potrzebnymi do przyszłych zapytań i odpowiednio modeluj swoje dane.