mongodb schema design For blogs
Jak zaprojektowałbyś schemat dla witryny podobnej do bloga z bazami danych bazującymi na dokumentach (mongodb). Na stronie znajdują się następujące obiekty: użytkownik, artykuł, komentarz. Użytkownik może dodawać komentarze do artykułu. Każdy użytkownik może również głosować dokładnie raz na komentarz.
Chcę móc sprawnie wykonywać te zapytania:
1. get Article A, comments on Article A and # of votes per comments
2. Otrzymuj wszystkie komentarze użytkownika B we wszystkich artykułach
3. get all comments User B voted for
Mój pierwsza próba to umieszczenie artykułów i komentarzy w osobnych kolekcjach, a komentarz może zawierać listę użytkowników, którzy na niego głosowali. To sprawia, że ZAPYTANIE 1 i 2 jest proste. A dla 3 dodałem kolekcję głosów, która przechowuje ślady głosów użytkowników.
Istnieje pewna oczywista wada, taka jak powielanie danych głosowania użytkowników, a ZAPYTANIE 1 będzie wymagało dwóch wywołań do bazy danych. Czy jest lepsze podejście?
Article {
"user_id"
}
Comment {
"user_id",
"article_id",
[user_voted],
}
Vote {
"user_id",
"comment_id",
}
1 answers
Article {
"_id" : "A",
"title" : "Hello World",
"user_id" : 12345,
"text" : 'My test article',
"comments" : [
{ 'text' : 'blah', 'user_id' : 654321, 'votes' : [987654]},
{ 'text' : 'foo', 'user_id' : 987654, 'votes' : [12345, 654321] },
...
]
}
Podstawową przesłanką jest to, że zagnieżdżam Comments
wewnątrz Article
. Votes
stosuje się tylko do Comment
, więc zostały one zapisane jako tablica z każdym Comment
. W tym przypadku właśnie zapisałem user_id. Jeśli chcesz przechowywać więcej informacji (time_created, itp.), następnie można wybrać tablicę obiektów:
... 'votes' : [ { user_id : 987654, ts : 78946513 } ] ...
Jak sprawnie wykonywać zapytania:
- Pobierz artykuł A, komentarze do artykułu A i # głosów na komentarze
db.articles.find( { _id : 'A' } )
To dostaje wszystko za pomocą jednego zapytania. Być może będziesz musiał wykonać logikę po stronie klienta, aby liczyć głosy za komentarz, ale jest to dość trywialne.
- Otrzymuj wszystkie komentarze użytkownika B we wszystkich artykułach
db.articles.ensureIndex( { "comments.user_id" : 1 } )
db.articles.find( { "comments.user_id" : 987654 } ) // returns all document fields
Indeks pozwoli na sprawne przeszukiwanie komentarzy w dokumencie.
Obecnie nie ma możliwości wyodrębnienia tylko dopasowań z tablicy podrzędnej. To zapytanie zwróci wszystkie artykuły z komentarze tego użytkownika. Jeśli jest to potencjalnie zbyt dużo danych, możesz wykonać przycinanie.
db.articles.find( { "comments.user_id" : 987654 }, { "title" : 1, "comments.user_id" : 1 })
- get all comments User B voted for
db.articles.ensureIndex( { "comments.votes" : 1 } )
db.articles.find( { "comments.votes" : 987654 } )
Ponownie, zwróci to wszystkie artykuły, nie tylko komentarze.
Jest tu kompromis. Zwrócenie artykułu może wydawać się, że przywracamy zbyt dużo danych. Ale co planujesz wyświetlić użytkownikowi, gdy wykonasz zapytanie #3?
Uzyskanie listy "komentarze, na które głosowałem" nie są zbyt przydatne bez samego komentarza. Oczywiście komentarz nie jest zbyt przydatny bez samego artykułu (a przynajmniej tylko tytułu).
Przez większość czasu zapytanie #3 przekształca się w połączenie z Votes
do Comments
do Articles
. Jeśli tak jest, to dlaczego po prostu nie przywrócić artykułów na początek?
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-03-07 23:30:38