MongoDB

Как лучше искать переписку в MongoDB перед созданием

Чтобы перед созданием переписки найти уже существующий чат в MongoDB, храните в документе стабильный ключ участников. Для личной переписки двух пользователей это может быть participantsKey, собранный из id пользователей в отсортированном порядке. Тогда один и тот же чат не будет создаваться дважды из-за разного порядка участников

Пример документа:

{
  _id: ObjectId("665f1c1a7b8c2e0012a4d111"),
  type: "direct",
  participants: [
    ObjectId("665f1c1a7b8c2e0012a4d001"),
    ObjectId("665f1c1a7b8c2e0012a4d002")
  ],
  participantsKey: "665f1c1a7b8c2e0012a4d001:665f1c1a7b8c2e0012a4d002",
  createdAt: new Date()
}

Ключ создается так: берете два id, сортируете, соединяете через :

Поиск перед созданием

const ids = [userA.toString(), userB.toString()].sort();
const participantsKey = ids.join(":");

const chat = await db.collection("conversations").findOne({
  type: "direct",
  participantsKey
});

if (chat) {
  return chat;
}

const result = await db.collection("conversations").insertOne({
  type: "direct",
  participants: [userA, userB],
  participantsKey,
  createdAt: new Date()
});

Так поиск не зависит от того, кто первым нажал «написать»

Индекс против повторов

Чтобы две одновременные попытки не создали две одинаковые переписки, добавьте уникальный индекс:

db.conversations.createIndex(
  { type: 1, participantsKey: 1 },
  { unique: true }
)

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

Практичный сценарий такой: пользователь нажал «написать», приложение строит participantsKey, пытается найти чат, а если его нет — создает. Если в этот же момент второй пользователь сделал то же самое, уникальный индекс станет последней защитой. Это нормальная архитектура: приложение старается найти существующий чат, база гарантирует, что повтор не появится

Для групповых чатов

Для группового чата логика другая. Там участники могут меняться, поэтому participantsKey не всегда подходит. Обычно создают документ чата один раз, а потом ищут его по _id. Для списка чатов пользователя используют запрос по массиву:

db.conversations.find({
  participants: userId
}).sort({ updatedAt: -1 })

Для такого запроса нужен индекс:

db.conversations.createIndex({ participants: 1, updatedAt: -1 })

Где хранить сообщения

Сообщения лучше хранить в отдельной коллекции:

{
  conversationId: ObjectId("665f1c1a7b8c2e0012a4d111"),
  senderId: ObjectId("665f1c1a7b8c2e0012a4d001"),
  text: "Привет",
  createdAt: new Date()
}

Так документ переписки не будет расти бесконечно

Для быстрого списка диалогов в документе переписки можно хранить lastMessageText, lastMessageAt и lastSenderId. Полный текст сообщений все равно остается в коллекции messages, но список чатов открывается быстро и не требует каждый раз искать последнее сообщение отдельным запросом

Как проверить

Создайте чат от пользователя A к B, потом попробуйте создать от B к A. Должен вернуться тот же документ, а не новый. Проверьте количество:

db.conversations.countDocuments({
  type: "direct",
  participantsKey
})

Ожидаемый результат — 1

Частые ошибки

Ищут по массиву без нормализации

Порядок участников может отличаться. Для личного чата лучше стабильный ключ

Не ставят уникальный индекс

Без индекса параллельные запросы могут создать повтор

Хранят все сообщения внутри переписки

Документ будет быстро расти. Сообщения лучше вынести отдельно

Не обновляют updatedAt

Без updatedAt список переписок сложно сортировать по последнему сообщению

Что почитать дальше по MongoDB

Если нужен общий маршрут по теме, откройте рубрику MongoDB. Для соседних задач пригодятся эти разборы:

Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные

Настройки cookie

0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x