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",
}
Author: kefeizhou, 2011-03-07

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:

  1. 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.

  1. 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 })
  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?

 29
Author: Gates VP,
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