#mongodb #schema #messaging
#mongodb #схема #обмен сообщениями
Вопрос:
У меня есть эта схема для поддержки обмена сообщениями на сайте:
Когда я отправляю сообщение другому участнику, сообщение сохраняется в таблице сообщений; запись добавляется в таблицу messageSent, а запись для каждого получателя добавляется в таблицу MessageInbox. MessageCount используется для отслеживания количества сообщений в папках входящих / отправленных и заполняется с помощью триггеров вставки / удаления в MessageInbox / messageSent — таким образом, я всегда могу узнать, сколько сообщений у участника, не выполняя дорогостоящий запрос «выбрать количество (*)».
Кроме того, когда я запрашиваю сообщения участника, я присоединяюсь к таблице участников, чтобы получить имя / фамилию участника.
Теперь я буду перемещать приложение в MongoDB, и я не совсем уверен, какой должна быть схема сбора. Поскольку в MongoDB нет доступных соединений, я должен полностью денормализовать ее, поэтому у меня должны быть коллекции MessageInbox, MessageDraft и messageSent с полной информацией о сообщении, верно?
Тогда я не уверен в следующем:
-
Что, если пользователь изменит свое имя / фамилию? В некоторых сообщениях она будет сохранена в денормализованном виде как отправитель, в других сообщениях как часть получателей — как мне обновить ее оптимальным образом?
-
Как мне получить количество сообщений? Одновременно будет поступать множество запросов, поэтому она должна работать хорошо.
Мы высоко ценим любые идеи, комментарии и предложения!
Ответ №1:
Я могу предложить вам некоторое представление о том, что я сделал для имитации объединений в MongoDB.
В подобных случаях я сохраняю ИДЕНТИФИКАТОР соответствующего пользователя (или нескольких пользователей) в заданном объекте, таком как ваш объект message в коллекции messages.
(Я не предлагаю, чтобы это была ваша схема, просто использую ее как пример моего подхода)
{
_id: "msg1234",
from: "user1234",
to: "user5678",
subject: "This is the subject",
body: "This is the body"
}
Я бы запросил базу данных, чтобы получить все нужные мне сообщения, затем в своем приложении я бы повторил результаты и создал массив идентификаторов пользователей. Я бы отфильтровал этот массив, чтобы он был уникальным, а затем повторно запросил базу данных, используя $in
оператор, чтобы найти любого пользователя в данном массиве.
Затем в моем приложении я бы присоединил результаты обратно к объекту.
Для этого требуется два запроса к базе данных (или, возможно, больше, если вы хотите присоединиться к другим коллекциям), но это иллюстрирует то, за что многие люди выступали в течение длительного времени: выполняйте ваши объединения на вашем прикладном уровне. Пусть база данных тратит свое время на запрос данных, а не на их обработку. Вероятно, вы в любом случае сможете масштабировать свои серверы приложений быстрее и дешевле, чем свою базу данных.
Я использую этот шаблон для создания каналов активности в реальном времени в моем приложении, и он работает безупречно и быстро. Я предпочитаю это денормализации вещей, которые могут измениться, например, информации о пользователе, потому что при записи в базу данных MongoDB может потребоваться перезаписать весь объект, если новые данные не помещаются на место старых данных. Если бы мне понадобилось переписать сотни (или тысячи) элементов activity в моей базе данных, то это было бы катастрофой.
Кроме того, записи в MongoDB блокируются, поэтому, если бы произошел сценарий, подобный тому, который я только что описал, все операции чтения и записи были бы заблокированы до завершения операции записи. Я полагаю, что этот вопрос планируется в какой-то степени решить в серии 2.x, но он все равно не будет идеальным.
С другой стороны, индексированные запросы выполняются очень быстро, даже если вам нужно выполнить два из них, чтобы получить данные.
Комментарии:
1. Это хорошая идея. Есть мысли о том, как эффективно собирать количество сообщений?
2. Вероятно, лучший способ сделать это — сохранить где-нибудь предварительно вычисленное количество. Планируется, что в MongoDB 2.x будут дополнительные операторы агрегирования, такие как $ sum, но пока этого не произошло. Для подобных случаев вы можете просто захотеть сохранить ее где-нибудь и использовать оператор $ inc для увеличения ее всякий раз, когда отправляется сообщение.