Подтвердить что ты не робот

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

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

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

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

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

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

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

4b9b3361

Ответ 1

{
_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 с вашим собственным уникальным идентификатором и upsert это в MongoDB. Если вам нужна большая гибкость (например, теги или папки), вы, вероятно, захотите сделать префикс для каждого получателя сообщения. Например, вы можете добавить:

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

для объекта prefs, а затем для получения всех префиксов всех сообщений с тегом "tech stuff" вы бы сделали что-то вроде:

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

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

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

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

Ответ 2

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

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

Затем вы можете индексировать это поле, создавая быстрые запросы для документов, читаемых по-пользователю и пользователям-who-read-Document.

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

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

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