Frage

Angenommen, Sie haben eine große Anzahl von Benutzern (M) und eine große Anzahl von Dokumenten (N), und Sie wollen, dass jeder Benutzer in der Lage sein, jedes Dokument als gelesen oder ungelesen zu markieren (wie jedes E-Mail-System). Was ist der beste Weg, dies in MongoDB zu vertreten? Oder jede andere Dokumentendatenbank?

Es gibt mehrere Fragen auf Stackoverflow diese Frage für relationale Datenbanken fragen, aber ich habe nicht mit Empfehlungen für Dokumentendatenbanken:

Was ist das effiziente Art und Weise gelesen / ungelesen Status über mehrere Artikel zu erinnern?

Implementierung eines effizienten Systems von „ungelesen Kommentare“ Zähler

Normalerweise beinhalten die Antworten eine Tabelle alles Auflistung ein Benutzer lesen: (dh Tupel von Benutzer-ID, Dokument-ID) mit einigen möglichen Optimierungen für eine Stichtags ermöglicht mark-all-as-lesen Sie die Datenbank löschen und wieder von vorn anfangen dass alles, was vor diesem Zeitpunkt weiß, ist ‚lesen‘.

So, MongoDB / NoSQL-Experten, welche Ansätze sie in der Praxis für dieses Problem gesehen haben und wie haben sie durchführen?

War es hilfreich?

Lösung

{
_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]
}

Say you have 3 messages you want to retrieve preferences for, you can get them via something like:

db.messages.find({
messageId : { $in : [messageId1,messageId2,messageId3]},
ownerId: receipientId, 
type:'prefs'
})

If all you need is read/unread you could use this with MongoDB's upsert capabilities, so you are not creating prefs for each message unless the user actually reads it, then basically you create the prefs object with your own unique id and upsert it into MongoDB. If you want more flexibility(like say tags or folders) you'll probably want to make the pref for each recipient of the message. For example you could add:

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

to the prefs object and then to get all the prefs of all the messages tagged with 'tech stuff' you'd go something like:

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

You could then use the messageIds you find within the prefs to query and find all the messages that correspond:

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

It might be a little tricky if you want to do something like counting how many messages each 'tag' contains efficiently. If it's only a handful of tags you can just add .count() to the end of your query for each query. If it's hundreds or thousands then you might do better with a map/reduce server side script or maybe an object that keeps track of message counts per tag per user.

Andere Tipps

If you're only storing a simple boolean value, like read/unread, another method is to embedded an array in each Document that contains a list of the Users who have read it.

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

You should then be able to index that field, making for fast queries for Documents-read-by-User and Users-who-read-Document.

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

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

However, I find that I'm usually querying for all Documents that have not been read by a particular User, and I can't think of any solution that can make use of the index in this case. I suspect it's not possible to make this fast without having both read_by and unread_by arrays, so that every User is included in every Document (or join table), but that would have a large storage cost.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top