#mongodb #schema #mongoid
#mongodb #схема #mongoid
Вопрос:
Я разрабатываю приложение, которое обрабатывает RSS-каналы с использованием MongoDB. В настоящее время мои коллекции следующие:
Entry
fields: content, feed_id, title, publish_date, url
Feed
fields: description, title, url
User
fields: email_address
subscriptions (embedded collection; fields: feed_id, tags)
Пользователь может подписаться на каналы, которые связаны из встроенной коллекции подписки. Из подписок я могу получить список всех каналов, которые должен видеть пользователь, а также соответствующие записи.
Как я должен хранить информацию о статусе записи (isRead, isStarred и т.д.), Специфичную для пользователя? Когда пользователь просматривает запись, которую мне нужно записать, isRead = 1. Два распространенных запроса, которые мне нужно выполнить, это:
- Найдите все записи для определенного канала, где isRead = 0 или статус не существует в данный момент
- Для конкретного пользователя отметьте все записи до даты публикации с помощью isRead = 1 (это могут быть сотни или даже тысячи записей, поэтому это должно быть эффективно)
Ответ №1:
Хм, это сложная задача!
Для меня имеет смысл сохранять записи для непрочитанных записей и удалять их при чтении. Я основываю это на предположении, что для каждого отдельного пользователя будет больше прочитанных сообщений, чем непрочитанных, поэтому у вас также может не быть документов для всех этих уже прочитанных записей, которые вечно хранятся в вашей БД. Это также упрощает задачу — не беспокоиться об ограничении размера документа в 16 МБ, если вам не нужно повсюду таскать с собой многолетнюю историю.
Для выделенных записей я бы просто добавил массив идентификаторов объектов записи для пользователя. Нет необходимости привязывать их к подписке; будет намного проще получить список элементов, которые пользователь выделил таким образом.
Для непрочитанных записей это немного сложнее. Я бы все равно добавил его в виде массива, но чтобы удовлетворить ваше требование о возможности быстрой пометки записей как прочитанных до определенной даты, я бы денормализовал и сохранил дату публикации вместе с идентификатором объекта записи в новом документе ‘UnreadEntry’.
User
fields: email_address, starred_entries[]
subscriptions (embedded collection; fields: feed_id, tags, unread_entries[])
UnreadEntry
fields: id is Entry ObjectId, publish_date
Вы должны помнить об ограничении документа, но 16 МБ — это чертовски много непрочитанных записей / каналов, поэтому будьте реалистичны в отношении того, действительно ли это ограничение, о котором вам нужно беспокоиться. (Если это так, должно быть довольно просто отключить User.subscriptions от своего собственного документа.)
Теперь оба ваших запроса становятся довольно простыми в написании:
Все непрочитанные записи для определенного канала: user.subscriptions.find(feedID).unread_entries
Отметьте все записи до даты публикации, прочитанные: user.subscriptions.find(feedID).unread_entries.where(publish_date.lte => my_date).delete_all
И, конечно, если вам просто нужно пометить все записи в ленте как прочитанные, это очень просто: user.subscriptions.find(feedID).unread_entries.delete_all