Question

Supposons que vous avez un grand nombre d'utilisateurs (M) et un grand nombre de documents (N) et que vous voulez que chaque utilisateur soit en mesure de marquer chaque document comme lu ou non lu (comme tout système de messagerie). Quelle est la meilleure façon de représenter cela dans MongoDB? Ou toute autre base de données de documents?

Il y a plusieurs questions sur StackOverflow poser cette question pour les bases de données relationnelles mais je ne vois pas de recommandations pour les bases de données de documents:

Quel est le plus moyen efficace de se rappeler l'état lu / non lu sur plusieurs éléments?

La mise en œuvre d'un système efficace de compteurs « commentaires non lus »

En général, les réponses comportent un tableau tout ce qu'un utilisateur a lu: (c.-à-tuples de l'ID utilisateur, ID du document) avec quelques optimisations possibles pour une date butoir permettant marque-tout-en-lu pour nettoyer la base de données et recommencer sachant que quoi que ce soit avant cette date est « lu ».

Alors, les experts MongoDB / NoSQL, quelles approches avez-vous vu dans la pratique à ce problème et comment ont-ils fait?

Était-ce utile?

La solution

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

Dites que vous avez 3 messages que vous souhaitez récupérer les préférences pour, vous pouvez les obtenir par quelque chose comme:

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

Si tout ce que vous avez besoin est lu / non lu, vous pouvez l'utiliser avec les capacités de upsert de MongoDB, de sorte que vous ne créez pas prefs pour chaque message à moins que l'utilisateur lit réellement, puis, fondamentalement, vous créez l'objet prefs avec votre propre identifiant unique et upsert dans MongoDB. Si vous voulez plus de flexibilité (comme les balises dites ou dossiers), vous aurez probablement envie de faire la pref pour chaque destinataire du message. Par exemple, vous pouvez ajouter:

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

aux prefs objet et pour obtenir tous les prefs de tous les messages marqués avec vous iriez quelque chose comme « stuff tech »:

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

Vous pouvez ensuite utiliser les messageIds que vous trouvez dans les prefs à la requête et trouver tous les messages qui correspondent:

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

Il est peut-être un peu délicat si vous voulez faire quelque chose comme le comptage le nombre de messages chaque « tag » contient efficacement. Si c'est seulement une poignée de balises que vous pouvez simplement ajouter .count() à la fin de votre requête pour chaque requête. Si elle est centaines ou des milliers alors vous pourriez faire mieux avec une map / reduce script côté serveur ou peut-être un objet qui garde la trace de nombre de messages par étiquette par utilisateur.

Autres conseils

Si vous ne le stockage d'une simple valeur booléenne, comme lu / non lu, une autre méthode consiste à un tableau intégré dans chaque document qui contient une liste des utilisateurs qui l'ont lu.

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

Vous devriez alors être en mesure d'indexer ce domaine, ce qui pour les requêtes rapides pour les documents en lecture par l'utilisateur et les utilisateurs-qui-lecture du document.

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

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

Cependant, je trouve que je suis généralement pour tous interroger des documents qui ont pas été lu par un utilisateur particulier, et je ne peux pas penser à une solution qui peut utiliser l'index ce cas. Je pense qu'il est impossible de faire ce jeûne sans avoir les deux tableaux read_by et unread_by, de sorte que chaque utilisateur est inclus dans chaque document (ou se joindre à la table), mais cela aurait un coût important de stockage.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top