124 votes

Principes pour la Modélisation de CouchDB Documents

J'ai une question que j'ai essayé de répondre pendant un certain temps maintenant, mais ne peuvent pas comprendre:

Comment pensez-vous de la conception, ou de répartir les, Documents des documents?

Prendre un billet de Blog par exemple.

Le semi "relationnel" façon de le faire serait de créer quelques objets:

  • Post
  • L'utilisateur
  • Commentaire
  • Tag
  • Extrait de

Cela fait beaucoup de sens. Mais je suis en train d'utiliser couchdb (pour toutes les raisons que c'est génial) pour modéliser la même chose et ça a été extrêmement difficile.

La plupart des messages de blog là vous donner un exemple simple de comment faire cela. Ils se sont contentés de le diviser de la même façon, mais dire que vous pouvez ajouter "arbitraire" des propriétés de chaque document, ce qui est certainement agréable. Donc, si vous voulez avoir quelque chose comme ceci dans CouchDB:

  • La poste (avec des balises et des extraits de "pseudo" modèles dans la doc)
  • Commentaire
  • L'utilisateur

Certaines personnes disent même que vous pourrait jeter le Commentaire et l'Utilisateur, de sorte que vous auriez à ceci:


C'est très joli et facile à comprendre. Je comprends aussi la façon dont vous pouvez écrire des vues extraites juste les Commentaires de tous vos Post les documents, les mettre en Commentaire les modèles, même avec les Utilisateurs et les Tags.

Mais je pense, "pourquoi ne pas simplement mettre mon site entier en un seul document?":


Vous pouvez facilement faire des vues de trouver ce que tu voulais.

Alors la question que je me pose est, comment voulez-vous déterminer le moment de diviser le document en petits documents, ou le moment de faire les "RELATIONS" entre les documents?

Je pense qu'il serait beaucoup plus "Orienté Objet", et plus facile à la carte pour des Objets de Valeur, si elle était divisée comme suit:


... mais ensuite, il se lance à la recherche de plus comme une Base de données Relationnelle. Et bien souvent, je hériter de quelque chose qui ressemble à la "toute-site-dans-un-document", il est donc plus difficile à modéliser avec les relations.

J'ai lu beaucoup de choses sur comment et quand utiliser les Bases de données Relationnelles vs Document de Bases de données, ce qui n'est pas le problème ici. Je suis plus juste de se demander, ce qui est une bonne règle/principe à appliquer lors de la modélisation de données CouchDB.

Un autre exemple est avec des fichiers XML/données. Certaines données XML a imbrication de+ de 10 niveaux de profondeur, et je voudrais visualiser qu'en utilisant le même client (Ajax sur des Rails par exemple, ou Flex) que je voudrais rendre JSON de ActiveRecord, CouchRest, ou tout autre Objet Relational Mapper. Parfois, je reçois des fichiers XML énormes qui sont toute la structure du site, comme celle ci-dessous, et j'aurais besoin de la carte pour des Objets de Valeur à utiliser dans mon application Rails, donc je n'ai pas à écrire une autre façon de sérialisation/désérialisation des données:


Ainsi, le général CouchDB questions sont les suivantes:

  1. Quelles sont les règles/principes utilisez-vous pour diviser vos documents (rapports, etc)?
  2. Est-il correct de mettre le site en entier en un seul document?
  3. Si oui, comment avez-vous gérer la sérialisation/désérialisation des documents arbitraire de niveaux de profondeurs (comme le grand json exemple ci-dessus, ou l'exemple de xml)?
  4. Ou ne vous mettez pas dans VOs, avez-vous venez de décider "ceux-ci sont trop imbriqués pour Objet-Relationnel Carte, donc je vais juste y accéder à l'aide de matières XML/JSON méthodes"?

Merci beaucoup pour votre aide, le problème de la manière de partager vos données avec CouchDB a été difficile pour moi de dire "c'est comment je dois faire à partir de maintenant". J'espère y arriver bientôt.

J'ai étudié les sites suivants/projets.

  1. Des Données hiérarchiques dans CouchDB
  2. CouchDB Wiki
  3. Canapé - CouchDB App
  4. CouchDB Le Guide Définitif
  5. PeepCode CouchDB Screencast
  6. CouchRest
  7. CouchDB README

...mais ils n'ont toujours pas répondu à cette question.

26voto

BigBlueHat Points 891

Il y a eu quelques grandes réponses à ce déjà, mais je voulais ajouter un peu plus récente CouchDB caractéristiques du mélange des options pour travailler avec l'original de la situation décrite par viatropos.

Le moment clé où de diviser les documents où il pourrait y avoir des conflits (comme mentionné précédemment). Vous ne devriez jamais garder massivement "tangled" documents en un document unique que vous aurez une seule révision chemin pour complètement sans rapport avec les mises à jour (commentaire plus de l'ajout d'une révision de l'ensemble du document du site par exemple). La gestion des relations ou des liens entre les différents documents de petite taille peut être déroutant au premier abord, mais CouchDB fournit plusieurs options pour combiner des morceaux disparates dans les réponses uniques.

La première grosse est la vue du classement. Lorsque vous émettez des paires clé/valeur dans les résultats d'une map/reduce requête, les touches sont classées sur la base de l'UTF-8 de classement ("a" vient avant "b"). Vous pouvez également sortie complexe des clés de votre map/reduce JSON tableaux: ["a", "b", "c"]. Faire cela vous permettra de comprendre un "arbre" de toutes sortes construit à partir de la matrice de touches. À l'aide de votre exemple ci-dessus, nous pouvons sortie de la post_id, puis le type de chose que nous sommes de référencement, puis son ID (si nécessaire). Si nous avons alors la sortie de l'id du document de référence vers un objet de valeur qui est retourné, nous pouvons utiliser la include_docs' requête de paramètre pour inclure ces documents dans le map/reduce de sortie:

{"rows":[
  {"key":["123412804910820", "post"], "value":null},
  {"key":["123412804910820", "author", "Lance1231"], "value":{"_id":"Lance1231"}},
  {"key":["123412804910820", "comment", "comment1"], "value":{"_id":"comment1"}},
  {"key":["123412804910820", "comment", "comment2"], "value":{"_id":"comment2"}}
]}

Demandant même point de vue avec"?include_docs=true' va ajouter un 'doc' clé qui permettra d'utiliser le '_id' référencé dans la "valeur" de l'objet ou, si cela n'est pas présent dans la "valeur" de l'objet, il va utiliser la '_id' du document à partir de laquelle la ligne a été émise (dans ce cas, le "post" du document). Veuillez noter que ces résultats incluent entre autres un champ 'id' référencement du document source à partir de laquelle l'emit a été faite. Je l'ai laissée pour l'espace et la lisibilité.

Nous pouvons alors utiliser "start_key" et "end_key" paramètres " pour filtrer les résultats à un seul post de données:

?start_key=["123412804910820"]&end_key=["123412804910820", {}, {}]

Ou même directement extrait de la liste pour un certain type:

?start_key=["123412804910820", "commentaire"]&end_key=["123412804910820", "commentaire", {}]

Ces requêtes param combinaisons sont possibles, car un objet vide ("{}") est toujours en bas du classement et de la valeur null ou "" sont toujours au top.

Le deuxième complément utile de CouchDB dans ces situations est la _list fonction. Cela vous permettra d'exécuter les résultats ci-dessus par le biais d'un système de template de quelque sorte (si vous voulez, HTML, XML, CSV ou que ce soit à l'arrière), ou la sortie d'un unifiée de la structure JSON si vous voulez être en mesure de demander un poste ensemble du contenu (y compris l'auteur et le commentaire de données) avec une seule requête et retourne comme un seul document JSON qui correspond à ce que votre client-side/code de l'INTERFACE utilisateur des besoins. Faire cela vous permettra de demander à la poste unifié du document de sortie de cette façon:

/db/_design/app/_list/posts/unifiée??start_key=["123412804910820"]&end_key=["123412804910820", {}, {}]&include_docs=true

Votre _list fonction (dans ce cas appelé "unifiée") serait de prendre les résultats de la vue map/reduce (dans ce cas appelé "posts") et de les exécuter via une fonction JavaScript qui permettrait de renvoyer la réponse HTTP dans le type de contenu dont vous avez besoin (JSON, HTML, etc).

La combinaison de ces choses, vous pouvez diviser vos documents quel que soit le niveau que vous trouvez utiles et de "sécurité" pour les mises à jour, des conflits, et de réplication, puis les remettre ensemble en tant que de besoin lorsqu'ils sont demandés.

Espérons que cela aide.

17voto

jake l Points 81

Je sais que c'est une vieille question, mais je suis tombé sur elle en essayant de trouver la meilleure approche à ce même problème. Christopher Lenz a écrit un joli billet de blog à propos des méthodes de modélisation des "jointures" dans CouchDB. Un de mes cadeaux: "La seule façon de permettre à des non-contradictoires plus de données liées à l'est en mettant que des données connexes dans des documents distincts." Ainsi, par souci de simplicité que vous souhaitez à se pencher vers la "dénormalisation". Mais vous serez frappé une barrière naturelle à cause du conflit entre l'écrit dans certaines circonstances.

Dans votre exemple de Posts et les Commentaires, si un seul post et toutes ses commentaires vécu dans un document, puis deux personnes essayant de poster un commentaire dans le même temps (c'est à dire à l'encontre de la même révision du document), il y aurait un conflit. Ce serait encore pire dans votre "site entier en un seul document" scénario.

Je pense donc que la règle sera de "dénormaliser jusqu'à ce que ça fait mal, mais au point où il va "mal" est l'endroit où vous avez une forte probabilité de multiples modifications étant posté à l'encontre de la même version d'un document.

16voto

Eero Points 1612

Le livre dit, si je me souviens bien, pour éliminer jusqu'à ce que "ça fait mal", tout en gardant à l'esprit la fréquence à laquelle vos documents peuvent être mis à jour.

  1. Quelles sont les règles/principes utilisez-vous pour diviser vos documents (rapports, etc)?

En règle générale, j'inclus toutes les données nécessaires à l'affichage d'une page en ce qui concerne l'élément en question. En d'autres termes, tout ce que vous pouvez imprimer sur une vraie feuille de papier que vous le feriez à la main à quelqu'un. E. g. une cotation boursière document comporterait le nom de la société, l'échange, la monnaie, en plus des nombres; un contrat document devrait inclure les noms et adresses des contreparties, toutes les informations sur les dates et les signataires. Mais la bourse de différentes dates forme de documents distincts, séparés les contrats seraient forme de documents distincts.

  1. Est-il correct de mettre le site en entier en un seul document?

Non, ce serait ridicule, parce que:

  • vous avez à lire et à écrire l'ensemble du site (le document) sur chaque mise à jour, et qui est très inefficace;
  • vous ne serait pas profiter d'une vue de mise en cache.

6voto

Riyad Kalla Points 6064

Je pense que Jake réponse de clous un des aspects les plus importants de travailler avec des Documents qui peuvent vous aider à faire de la portée de la décision: des conflits.

Dans le cas où vous avez des commentaires comme un tableau de la propriété de la poste elle-même, et vous avez juste un 'post' DB avec un énorme tas de "post" documents, comme Jake et les autres correctement souligné que l'on pouvait imaginer un scénario sur un très populaire blog où deux utilisateurs de soumettre des modifications à la poste le document simultanément, entraînant une collision et un conflit de version de ce document.

APARTÉ: Comme cet article le souligne, également considérer que chaque fois que vous demandez/mise à jour de la doc, vous devez obtenir/définir le document dans son intégralité, afin de passer un massif de documents qui représentent l'ensemble du site ou un poste avec beaucoup de commentaires sur il peut devenir un problème, vous voulez éviter.

Dans le cas où les postes sont modélisées séparément à partir d'observations et de deux personnes soumettre un commentaire sur une histoire, ceux qui se contentent de devenir deux "commentaire" des documents dans la DB, pas de problème de conflit; il suffit de METTRE deux opérations d'ajouter deux nouveaux commentaires sur le "commentaire" de la db.

Puis écrire le point de vue que vous donner les commentaires pour ce post, vous passerez dans le postID et puis émet tous les commentaires qui font référence à ce parent post ID, triés par certains de l'ordre logique. Peut-être vous même passer par quelque chose comme [postID,byUsername] comme la clé de la "commentaires" vue d'indiquer le parent post et comment vous voulez que les résultats triés ou quelque chose le long de ces lignes.

MongoDB traite des documents un peu différemment, permettant index construit sur sous-éléments d'un document, donc vous pouvez voir la même question sur la MongoDB liste de diffusion et que quelqu'un en disant "juste faire les commentaires une propriété de la mère de poste".

En raison de l'écriture de verrouillage et unique maître de la nature de Mongo, le conflit de révision de la question de deux personnes, l'ajout de commentaires ne serait pas le printemps là-haut et à la requête de la capacité du contenu, comme mentionné, n'est pas effectuée trop mal parce que des sous-indices.

Cela étant dit, si votre sous-éléments en soit DB va être énorme (dire 10s de milliers de commentaires) je crois que c'est la recommandation des deux camps à faire de ces éléments séparés; j'ai certainement vu que ce serait le cas avec Mongo car il y a des limite supérieure des limites sur la façon dont grand un document et de ses sous-éléments peuvent être.

1voto

user180154 Points 354

Riak a un premier concept de classe dans leur système que l'on appelle des "Liens", que l'essentiel de permettre des relations de fonctionnalités entre la Valeur de la Clé de magasins.

https://wiki.basho.com/display/RIAK/Links

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X