Domanda

Supponiamo di avere un gran numero di utenti (M) e un gran numero di documenti (N) e si desidera che ogni utente sia in grado di marcare ogni documento letti o da leggere (come qualsiasi sistema di posta elettronica). Qual è il modo migliore per rappresentare questo in MongoDB? O qualsiasi altro database di documenti?

Ci sono diverse domande su StackOverflow questa domanda per i database relazionali, ma non ho visto alcuna con le raccomandazioni per i database di documenti:

Qual è la più modo efficace per ricordare di lettura / stato non letto su più macchine?

Implementazione di un efficiente sistema di "commenti" non letti i contatori

In genere le risposte coinvolgono una tabella che elenca tutto ciò che un utente ha letto: (cioè tuple di id utente, documento di identità), con alcune possibili ottimizzazioni per un cut-off date permettendo mark-tutto-da-leggere per pulire il database e ricominciare sapendo che qualsiasi cosa prima di tale data è 'leggere'.

Quindi, gli esperti MongoDB / NoSQL, che si avvicina avete visto in pratica a questo problema e come si è comportata?

È stato utile?

Soluzione

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

Di 'si dispone di 3 messaggi che si desidera recuperare le preferenze per, si possono ottenere via qualcosa del tipo:

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

Se tutto ciò che serve è letto / non letto si potrebbe usare questo con funzionalità upsert di MongoDB, in modo che non si sta creando preferenze per ciascun messaggio, a meno che l'utente in realtà lo legge, quindi fondamentalmente si creano le preferenze oggetto con il proprio ID e upsert in MongoDB. Se si desidera una maggiore flessibilità (come i tag dire o cartelle) che probabilmente vuole fare il pref per ogni destinatario del messaggio. Per esempio si potrebbe aggiungere:

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

per le preferenze oggetto e quindi di ottenere tutte le preferenze di tutti i messaggi taggati con 'roba di tecnologia' devi andare qualcosa come:

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

È quindi possibile utilizzare i messageIds puoi trovare all'interno del prefs per interrogare e trovare tutti i messaggi che corrispondono:

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

Potrebbe essere un po 'difficile se si vuole fare qualcosa di simile conteggio quanti messaggi ogni 'tag' contiene in modo efficiente. Se è solo una manciata di tag si può semplicemente aggiungere .count() alla fine della query per ogni query. Se si tratta di centinaia o migliaia allora si potrebbe fare meglio con una mappa / ridurre script lato server o forse un oggetto che tiene traccia dei conteggi dei messaggi per tag per utente.

Altri suggerimenti

Se si sta solo la memorizzazione di un semplice valore booleano, come letto / non letto, un altro metodo è quello incorporato un array in ogni documento che contiene un elenco degli utenti che lo hanno letto.

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

Si dovrebbe quindi essere in grado di indicizzare quel campo, rendendo per le query veloci per i documenti-read-by-user e utenti-che-lettura del documento.

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

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

Tuttavia, trovo che sto di solito l'esecuzione di query per tutti i documenti che sono non stato letto da un particolare utente, e non riesco a pensare di qualsiasi soluzione che può fare utilizzo dell'indice in questo caso. Ho il sospetto che non è possibile fare questo veloce senza avere entrambi gli array read_by e unread_by, in modo che ogni utente è incluso in ogni documento (o partecipare tabella), ma che avrebbe un costo di stoccaggio di grandi dimensioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top