MongoDB / NOSQL: лучший подход к обработке прочитанного / непрочитанного статуса в сообщениях - PullRequest
13 голосов
/ 15 ноября 2010

Предположим, у вас есть большое количество пользователей (M) и большое количество документов (N), и вы хотите, чтобы каждый пользователь мог пометить каждый документ как прочитанный или непрочитанный (как в любой системе электронной почты). Какой лучший способ представить это в MongoDB? Или любая другая база документов?

В StackOverflow есть несколько вопросов, задающих этот вопрос для реляционных баз данных, но я не видел ни одного с рекомендациями для баз данных документов:

Какой самый эффективный способ запомнить состояние чтения / непрочитания для нескольких элементов?

Внедрение эффективной системы счетчиков "непрочитанных комментариев"

Обычно ответы включают таблицу со списком всего, что прочитал пользователь: (т. Е. Наборы идентификатора пользователя, идентификатора документа) с некоторыми возможными оптимизациями для даты отсечения, позволяющей пометить все как прочитанные, чтобы стереть базу данных и начать заново зная, что что-либо до этой даты «прочитано».

Итак, эксперты MongoDB / NOSQL, какие подходы вы видели на практике к этой проблеме и как они справились?

Ответы [ 2 ]

5 голосов
/ 15 ноября 2010
{
_id: messagePrefs_uniqueId,
type: 'prefs',
timestamp: unix_timestamp
ownerId: receipientId,
messageId: messageId,
read: true / false,
}

{
_id: message_uniqueId,
timestamp: unix_timestamp
type: 'message',
contents: 'this is the message',
senderId: senderId,
recipients: [receipientId1,receipientId2]
}

Скажем, у вас есть 3 сообщения, для которых вы хотите получить настройки, вы можете получить их через что-то вроде:

db.messages.find({
messageId : { $in : [messageId1,messageId2,messageId3]},
ownerId: receipientId, 
type:'prefs'
})

Если вам нужно только чтение / непрочитанное, вы можете использовать это с возможностями upsert MongoDB, так что вы не создаете prefs для каждого сообщения, если пользователь фактически не читает его, тогда в основном вы создаете объект prefs с вашим собственным уникальным id и upsert это в MongoDB. Если вам нужна большая гибкость (например, теги или папки), вы, вероятно, захотите сделать преф для каждого получателя сообщения. Например, вы можете добавить:

tags: ['inbox','tech stuff']

к объекту prefs, а затем, чтобы получить все prefs всех сообщений, помеченных «техническими вещами», вы должны сделать что-то вроде:

db.messages.find({type: 'prefs', ownerId: recipientId, tags: 'tech stuff'})

Затем вы можете использовать messageIds, которые вы найдете в префе, для запроса и поиска всех сообщений, которые соответствуют:

db.messages.find((type:'message', _id: { $in : [array of messageIds from prefs]}})

Может быть немного сложно, если вы захотите сделать что-то вроде подсчета количества сообщений, которые каждый тег содержит эффективно. Если это всего лишь несколько тегов, вы можете просто добавить .count() в конец вашего запроса для каждого запроса. Если это сотни или тысячи, то вы могли бы лучше использовать сценарий map / Reduce на стороне сервера или, возможно, объект, который отслеживает количество сообщений на тег для каждого пользователя.

3 голосов
/ 31 августа 2017

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

{
  _id: 'document#42',
  ...
  read_by: ['user#83', 'user#2702']
}

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

db.documents.find({read_by: 'user#83'})

db.documents.find({_id: 'document#42}, {read_by: 1})

ОднакоЯ обнаружил, что обычно запрашиваю все документы, которые не были прочитаны определенным пользователем, и я не могу придумать какое-либо решение, которое может использовать индекс в этом случае.Я подозреваю, что невозможно сделать это быстро, не имея массивов read_by и unread_by, так что каждый пользователь включен в каждый документ (или таблицу соединений), но это будет иметь большие затраты на хранение.

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