Предложения схемы уведомлений Mongoose/MongoDB

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

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

Вариант 1

Схема встроенных уведомлений

Notifications = new Schema ( {
    message : String,
    date : { type : Date, default: Date.now() }
    read : { type: Boolean, default : false }
});

User = new Schema( {
    username : String,
    name : String,
    notifications : [Notifications]
});

Плюсы:

  • Очень легко отобразить данные, так как вызов User.find() будет отображать уведомления в виде объекта массива.

Минусы:

  • Когда вы создаете уведомление для каждого пользователя, вам нужно сделать .push для всех встроенных уведомлений
  • Несколько записей уведомлений для каждого пользователя (несколько данных в базе данных)
  • Гигантский встроенный документ (я прочитал что-то о ограничении на 4 МБ)
  • Так как это встроенный документ - (mongoose DocumentArray), вы не можете выполнить поиск или пропустить. Вы загружаете каждое уведомление каждый раз, когда получаете доступ к пользователю.

Вариант второй

Объекты Populate (DBRef like)

Notification = new Schema ({
    message : String,
    date : { type : Date, default : Date.now() }
});

UserNotification = new Schema ({
    user : { type : Schema.ObjectId, ref : 'User' },
    notification : { type : Schema.ObjectId, ref : 'Notification' },
    read : { type : Boolean, default : false }
});

User = new Schema( {
    username : String,
    name : String,
    notifications : [ { type : Schema.ObjectID, ref : 'UserNotification' } ]
});

Плюсы:

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

Минусы:

  • У вас есть 3 коллекции, а не одна ( Вариант 1 имеет только одну коллекцию)
  • У вас есть 3 запроса при каждом доступе к коллекции.

Вопросы

  • Как вы думаете, самая лучшая схема из этих двух?
  • Я пропустил что-то или какое-то базовое знание NoSQL?
  • Может ли кто-нибудь предложить лучшую схему?

Спасибо, заранее, и я прошу прощения за длинный пост, но я думаю, что я не могу объяснить это проще.

Ответы

Ответ 1

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

Вариант 2 Я не совсем понимаю вашу стратегию - кажется, излишне иметь эти 3 коллекции, но также встраивать список уведомлений с помощью objectId, если вы уже ссылаетесь на пользователя по ID в таблице уведомлений. Вы можете индексировать пользователя в таблице "Уведомления", а затем исключить вложенный массив в таблице "Пользователи".

(РЕДАКТИРОВАТЬ) Вот еще одна стратегия для рассмотрения.

Три коллекции, которые выглядят следующим образом:

Users:
   _id: objectid
   username : string
   name: string

Notifications:
   _id:  objectid
   to (indexed):   objectid referencing _id in "users" collection
   read: boolean

Global Notifications:
   _id: objectid
   read_by: [objectid referencing _id in users]

Для уведомлений, предназначенных для одного пользователя, вставьте в Уведомления для этого пользователя. Для нескольких пользователей вставьте один для каждого пользователя (поочередно, вы можете сделать "to" полевым массивом и сохранить _ids всех получателей, а затем сохранить другой список всех получателей, которые его прочитали). Чтобы отправить уведомление всем пользователям, вставьте в коллекцию глобальных уведомлений. Когда пользователь прочитает его, добавьте их user_id в поле read_by. Итак, чтобы получить список всех непрочитанных уведомлений пользователя, вы выполняете два запроса: один для уведомлений и один для глобальных уведомлений.

Ответ 2

`// namespace like a channel
// we have a notification from specific channel or namespace
const NamespaceSchema = new Schema({
  name: {
    type: String,
    unique: true,
    required: true
  },
  author: {
    type: String,
    required: true
  },
  createdAt: {
    type: Boolean,
    default: Date.now()
  },
  notifications: [{
    type: Schema.Types.ObjectId,
    ref: 'Notification',
  }]
});`


`// the notification schema have a subscribers to specific notification (objectId)
//
const NotificationSchema = new Schema({
  title: {
    type: String
  },
  message: {
    type: String
  },
  read: {
    type: Boolean,
    default: false
  },
  subscribers: [{
    type: Schema.Types.ObjectId,
    ref: 'Subscriber'
  }],
  createdAt: {
    type: Date,
    default: Date.now()
  }
});`

`// subscribers subscribe to a namespace or channel
const SubscriberSchema = new Schema({
  subscriber: {
    type: String,
    required: true
  },
  namespaces: [{
    type: Schema.Types.ObjectId,
    ref: 'Namespace',
  }]
});`