Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose / MongoDB User notifications scheme suggestions

Tags:

I was wondering what is the best scheme for user/notifications kind of scenario like the following :

  • You have multiple users.
  • You have multiple notifications that might be for a single user, for some users or for all users.
  • You need a notification "read" entry in the storage, to know if the user has read the notification or not.

Option One

Embedded notifications scheme

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]
});

Pros :

  • It is very easy to display the data, since calling User.find() will display notifications as array object.

Cons :

  • When you create a notification for every user, you need to do .push to every embedded Notifications
  • Multiple notifications entries for every user ( multiple data in the database )
  • Giant embedded document ( I read something about <4MB limit of those )
  • Since it is a Embedded Document - ( mongoose DocumentArray ) you can't search or skip. You load every notifications everytime you access user.

Option Two

Populate (DBRef like) objects

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' } ]
});

Pros :

  • Optimal for queries
  • No duplicate data
  • Supporting large amount of notifications

Cons :

  • You have 3 collections, instead of one in ( Option One has only one collection )
  • You have 3 queries every time you access the collection.

Questions

  1. What do you think is the best scheme from those two?
  2. Am I missing something or some kind of basic NoSQL knowledge?
  3. Can someone propose better scheme?

Thank you, in advance and I'm sorry for the long post, but I think I can't explain it simpler.

like image 865
drinchev Avatar asked Apr 01 '12 15:04

drinchev


1 Answers

Option 1 looks like it will probably result in a lot of excessive document growth and moves, which would be bad for performance, since most of your writes will be going to the embedded doc (Notifications).

Option 2 I'm not totally clear on your strategy - it seems redundant to have those 3 collections but also embed a list of notifications by objectId if you are already referencing user by ID in the notifications table. You could index on user in Notifications table, and then eliminate the nested array in the Users table.

(EDIT) Here's another strategy to consider.

Three collections that look like this:

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]

For notifications meant for a single user, insert into Notifications for that user. For multiple users, insert one for each user (alternately, you could make the "to" field an array and store _ids of all the recipients, and then maintain another list of all the recipients who have read it). To send a notification to all users, insert into Global Notifications collection. When the user reads it, add their user's _id to the read_by field. So, to get a list of all the unread notifications of a user, you do two queries: one to notifications, and one to global notifications.

like image 63
mpobrien Avatar answered Sep 30 '22 12:09

mpobrien