2010-11-15 13 views
11

Supongamos que tiene una gran cantidad de usuarios (M) y una gran cantidad de documentos (N) y desea que cada usuario pueda marcar cada documento como leer o no leer (al igual que cualquier sistema de correo electrónico). ¿Cuál es la mejor manera de representar esto en MongoDB? O cualquier otra base de datos de documentos?MongoDB/NOSQL: mejor enfoque para manejar el estado leído/no leído en los mensajes

Hay varias preguntas sobre stackoverflow hace esta pregunta para bases de datos relacionales, pero no vi ninguna de las recomendaciones de bases de datos documentales:

What's the most efficient way to remember read/unread status across multiple items?

Implementing an efficient system of "unread comments" counters

Normalmente las respuestas implican un cuadro en el todo lo que un usuario ha leído: (es decir, tuplas de identificación de usuario, identificación de documento) con algunas optimizaciones posibles para una fecha de corte que permite que mark-all-as-read limpie la base de datos y comience de nuevo sabiendo que todo lo anterior se lee '.

Así que, expertos en MongoDB/NOSQL, ¿qué enfoques han visto en la práctica sobre este problema y cómo se han desempeñado?

Respuesta

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

Digamos que tienes 3 mensajes que desea recuperar las preferencias para, usted puede conseguir a través de algo como:

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

Si todo lo que necesita es de lectura/no leídos que podría utilizar esto con capacidades upsert de MongoDB , por lo que no está creando preferencias para cada mensaje a menos que el usuario realmente lo lea, entonces básicamente crea el objeto de preferencias con su propia identificación única y la inserta en MongoDB. Si desea más flexibilidad (como decir etiquetas o carpetas), probablemente desee hacer el pref de cada destinatario del mensaje. Por ejemplo, usted podría agregar:

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

a las Preferencias objeto y después de obtener todos los de preferencias de todos los mensajes etiquetados con 'tecnología cosas' que iría algo como:

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

Usted podría a continuación, utilizar los messageids que usted encuentra dentro de las Preferencias para consultar y encontrar todos los mensajes que corresponden:

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

podría ser un poco difícil si usted quiere hacer algo como contar cuántos mensajes cada 'etiqueta' contiene de manera eficiente. Si solo se trata de un puñado de etiquetas, puede agregar .count() al final de su consulta para cada consulta. Si se trata de cientos o de miles, puede que sea mejor con un script de mapa/reducir el lado del servidor o tal vez un objeto que realice un seguimiento de los recuentos de mensajes por etiqueta y usuario.

+1

Gracias, por lo que su recomendación es esencialmente el mismo tipo de tabla 'tuple/join' que el caso relacional, ¿no? ¿Alguna razón en particular para almacenar los mensajes y las preferencias en la misma colección? –

+0

Lo que sucede con MongoDB es que, por lo general, cuanto más plano pueda hacer su objeto, mejor. Si bien puede almacenar estructuras anidadas, no es lo mejor para consultar o entrar en esas estructuras para luego alterarlas. Así que muchas cosas pueden terminar pareciéndose a una relación, pero con menos abstracción debido a que no se usan tablas. Además, realmente no hay ninguna razón por la que los almacene en la misma colección, aparte de que no les gusta tener colecciones de millones de dólares. Si planea tener millones de mensajes, podría ser conveniente usar diferentes colecciones para que pueda configurar los índices para que se ajusten mejor a cada objeto. – Klinky

3

Si solo está almacenando un valor booleano simple, como leer/no leer, otro método es incrustar una matriz en cada documento que contiene una lista de los usuarios que lo han leído.

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

continuación, debería ser capaz de indexar ese campo, para hacer consultas rápidas para documentos leídos por usuario y Usuarios-Documento que-lectura.

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

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

Sin embargo, me parece que estoy por lo general las consultas a todos los documentos que tienen no sido leído por un usuario en particular, y no puedo pensar en ninguna solución que pueda hacer uso del índice en este caso.Sospecho que no es posible hacerlo tan rápido sin tener las dos matrices read_by y unread_by, por lo que cada usuario está incluido en cada documento (o tabla de unión), pero eso tendría un gran costo de almacenamiento.

+0

En relación con el último punto sobre la consulta de mensajes * no leídos * pero utilizando un campo * read_by *, corrígeme si me equivoco pero no pude lograr una cláusula ** $ not **, como en '$ not: {$ en: [{id: 'usuario # 83'}]} '? – bigp

Cuestiones relacionadas