Разработка схемы mongodb для блогов - PullRequest
28 голосов
/ 07 марта 2011

Как бы вы разработали схему для блогового сайта с базой данных на основе документов (mongodb). На сайте есть следующие объекты: Пользователь, Статья, Комментарий. Пользователь может добавлять комментарии к статье. Каждый пользователь также может проголосовать ровно один раз за комментарий.

Я хочу иметь возможность эффективно выполнять эти запросы:
1. получить статью А, комментарии к статье А и количество голосов за комментарии
2. получить все комментарии пользователя B по всем статьям
3. получить все комментарии Пользователь B проголосовал за

Моя первая попытка - поместить статьи и комментарии в отдельные сборники, и комментарий может содержать список пользователей, которые проголосовали за него. Это делает запрос 1 и 2 простым. А для 3 я добавил коллекцию голосования, которая отслеживает голоса пользователей.

Существует некоторый очевидный недостаток, такой как дублирование данных голосования пользователей, и запрос 1 будет выполнять два вызова в базу данных. Есть ли лучший подход?

Article {
  "user_id"
}

Comment {
   "user_id",
   "article_id",
   [user_voted],
}

Vote {
    "user_id",
    "comment_id",
}

1 Ответ

32 голосов
/ 08 марта 2011
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] },
    ...
  ]
}

Основная предпосылка здесь заключается в том, что я вложил Comments внутрь Article.Votes применяется только к Comment, поэтому они хранятся в виде массива с каждым Comment.В этом случае я только что сохранил user_id.Если вы хотите хранить больше информации (time_created и т. Д.), То вы можете проголосовать за массив объектов:

... 'votes' : [ { user_id : 987654, ts : 78946513 } ] ...

Как эффективно выполнять ваши запросы:

  1. получить статью A, комментарии к статье A и количество голосов в комментариях
db.articles.find( { _id : 'A' } )

Все получится одним запросом.Возможно, вам придется выполнить некоторую клиентскую логику для подсчета голосов за комментарий, но это довольно тривиально.

  1. получить все комментарии пользователя B по всем статьям
db.articles.ensureIndex( { "comments.user_id" : 1 } )
db.articles.find( { "comments.user_id" : 987654 } ) // returns all document fields

Индекс позволит эффективно искать комментарии в документе.

В настоящее время нет способа извлечь только совпадения из подмассива.Этот запрос фактически вернет все статьи с комментариями этого пользователя.Если это потенциально слишком много данных, вы можете сделать некоторую обрезку.

db.articles.find( { "comments.user_id" : 987654 }, { "title" : 1, "comments.user_id" : 1 })
  1. получить все комментарии Пользователь B проголосовал за
db.articles.ensureIndex( { "comments.votes" : 1 } )
db.articles.find( { "comments.votes" : 987654 } )

Опять же, это вернет все статьи, а не только комментарии.

Здесь нужно найти компромисс.Возвращение статьи может показаться, что мы возвращаем слишком много данных.Но что вы планируете показывать пользователю, когда делаете запрос № 3?

Получение списка "комментариев, за которые я голосовал" , не очень полезно без самого комментария.Конечно, комментарий не очень полезен без самой статьи (или хотя бы только заголовка).

В большинстве случаев запрос № 3 превращается в соединение от Votes до Comments до Articles.Если это так, то почему бы просто не вернуть статьи для начала?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...