web-dev-qa-db-fra.com

Relations MongoDB: intégration ou référence?

Je suis nouveau sur MongoDB - venant d’une base de données relationnelle. Je veux concevoir une structure de questions avec quelques commentaires, mais je ne sais pas quelle relation utiliser pour les commentaires: embed ou reference?

Une question avec des commentaires, comme stackoverflow , aurait une structure comme celle-ci:

Question
    title = 'aaa'
    content = bbb'
    comments = ???

Au début, je veux utiliser les commentaires intégrés (je pense que embed est recommandé dans MongoDB), comme ceci:

Question
    title = 'aaa'
    content = 'bbb'
    comments = [ { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'} ]

C'est clair, mais je suis inquiet à propos de ce cas: Si je veux éditer un commentaire spécifié, comment puis-je obtenir son contenu et sa question? Il n’ya pas de _id pour me laisser en trouver un, ni question_ref pour me laisser trouver sa question. (Je suis tellement novice que je ne sais pas s'il est possible de faire cela sans _id et question_ref.)

Dois-je utiliser ref pas embed? Ensuite, je dois créer une nouvelle collection pour les commentaires?

476
Freewind

C'est plus un art qu'une science. Le Documentation Mongo sur les schémas est une bonne référence, mais voici quelques points à considérer:

  • Mettre autant que possible

    La joie d'une base de données de document est qu'elle élimine beaucoup de jointures. Votre premier instinct devrait être de placer autant que possible dans un seul document. Comme les documents MongoDB ont une structure et que vous pouvez interroger efficacement au sein de cette structure (cela signifie que vous pouvez prendre la partie du document dont vous avez besoin, la taille du document ne devrait donc pas trop vous inquiéter), il n'est pas nécessaire de normaliser les données telles que vous le feriez en SQL. En particulier, toute donnée qui ne serait utile en dehors de son document parent devrait faire partie du même document.

  • Séparez les données auxquelles on peut faire référence à partir de plusieurs endroits dans sa propre collection.

    Ce n'est pas tant un problème "d'espace de stockage" que c'est un problème de "cohérence des données". Si de nombreux enregistrements font référence aux mêmes données, il est plus efficace et moins sujet aux erreurs de mettre à jour un seul enregistrement et de conserver les références à d'autres endroits.

  • Considérations relatives à la taille du document

    MongoDB impose une limite de taille de 4 Mo (16 Mo avec 1,8) à un seul document. Dans un monde de Go de données, cela semble petit, mais ce sont aussi 30 000 tweets ou 250 réponses typiques de Stack Overflow ou 20 photos scintillantes. D'autre part, il s'agit de beaucoup plus d'informations que l'on pourrait vouloir présenter en même temps sur une page Web typique. Considérons d’abord ce qui facilitera vos requêtes. Dans de nombreux cas, l’optimisation prématurée est un sujet de préoccupation.

  • Structures de données complexes:

    MongoDB peut stocker des structures de données imbriquées profondes arbitraires, mais ne peut pas les rechercher efficacement. Si vos données forment un arbre, une forêt ou un graphique, vous devez effectivement stocker chaque nœud et ses bords dans un document séparé. (Notez qu'il existe des magasins de données spécialement conçus pour ce type de données qu'il convient également de prendre en compte.)

    Il a également été signalé qu'il est impossible de renvoyer un sous-ensemble d'éléments dans un document. Si vous devez sélectionner quelques éléments de chaque document, il sera plus facile de les séparer.

  • La cohérence des données

    MongoDB fait un compromis entre efficacité et cohérence. La règle est que les modifications apportées à un seul document sont toujours atomiques, tandis que les mises à jour de plusieurs documents ne doivent jamais être considérées comme atomiques. Il n'y a également aucun moyen de "verrouiller" un enregistrement sur le serveur (vous pouvez l'intégrer dans la logique du client en utilisant, par exemple, un champ "verrouillé"). Lorsque vous concevez votre schéma, réfléchissez à la manière dont vous maintiendrez la cohérence de vos données. En règle générale, plus vous conservez dans un document, mieux c'est.

Pour ce que vous décrivez, je voudrais incorporer les commentaires et donner à chaque commentaire un champ id avec un ObjectID. ObjectID a un horodatage intégré pour que vous puissiez l'utiliser au lieu de créer à si vous le souhaitez.

717
John F. Miller

Si je veux éditer un commentaire spécifié, comment obtenir son contenu et sa question?

Vous pouvez interroger par sous-document: db.question.find({'comments.content' : 'xxx'}).

Ceci renverra le document entier de Question. Pour éditer le commentaire spécifié, vous devez ensuite rechercher le commentaire sur le client, le modifier et le sauvegarder dans la base de données.

En général, si votre document contient un tableau d'objets, vous constaterez que ces sous-objets devront être modifiés côté client.

31
Gates VP

En général, l'incorporation est bonne si vous avez des relations un à un ou un à plusieurs entre entités, et la référence est bonne si vous avez plusieurs relations à plusieurs.

30
ywang1724

Eh bien, je suis un peu en retard, mais j'aimerais quand même partager ma façon de créer un schéma.

J'ai des schémas pour tout ce qui peut être décrit par un mot, comme vous le feriez dans la POO classique.

PAR EXEMPLE.

  • Commentaire
  • Compte
  • Utilisateur
  • Blogpost
  • ...

Chaque schéma peut être enregistré en tant que document ou sous-document, je le déclare donc pour chaque schéma.

Document:

  • Peut être utilisé comme référence. (Par exemple, l'utilisateur a fait un commentaire -> le commentaire a une référence "fait par" à l'utilisateur)
  • Est-ce une "racine" dans votre application. (Par exemple, blogpost -> il y a une page sur le blogpost)

Sous-document:

  • Ne peut être utilisé qu'une seule fois/n'est jamais une référence. (Le commentaire, par exemple, est enregistré dans l'article de blog)
  • N'est jamais une "racine" dans votre application. (Le commentaire apparaît simplement dans la page blogpost mais la page est toujours à propos de blogpost)
20
Silom

Je suis tombé sur cette petite présentation en effectuant moi-même des recherches sur cette question. J'ai été surpris de la qualité de sa présentation, des informations et de la présentation.

http://openmymind.net/Multiple-Collections-Versus-Embedded-Documents

Il résume:

En règle générale, si vous avez beaucoup de [documents enfants] ou s'ils sont volumineux, une collection séparée peut être préférable.

Les documents plus petits et/ou moins nombreux ont tendance à être un choix naturel pour l'intégration.

18
Chris Bloom

Je sais que c'est assez ancien, mais si vous cherchez la réponse à la question de l'OP sur la façon de ne renvoyer que les commentaires spécifiés, vous pouvez utiliser l'opérateur $ (requête) comme ceci:

db.question.update({'comments.content': 'xxx'}, {'comments.$': true})
17
finspin

Si je veux éditer un commentaire spécifié, comment puis-je obtenir son contenu et sa question?

Si vous aviez noté le nombre de commentaires et l'index du commentaire que vous vouliez modifier, vous pourriez utiliser l'opérateur point ( exemple SO ).

Vous pourriez faire f.ex.

db.questions.update(
    {
        "title": "aaa"       
    }, 
    { 
        "comments.0.contents": "new text"
    }
)

(comme un autre moyen de modifier les commentaires dans la question)

1
serv-inc

J'ai créé ce quizz comme référence pour savoir si vous devriez utiliser l'un ou l'autre

http://indie-rok.github.io/embedded-vs-reference-mongo-db

1
Emmanuel Orozco

En fait, je suis assez curieux de savoir pourquoi personne ne parle des spécifications UML. En règle générale, si vous avez une agrégation, vous devez utiliser des références. Mais s'il s'agit d'une composition, le couplage est plus fort et vous devez utiliser des documents incorporés.

Et vous allez vite comprendre pourquoi c'est logique. Si un objet peut exister indépendamment du parent, vous souhaiterez y accéder même si le parent n'existe pas. Comme vous ne pouvez pas l'intégrer dans un parent non existant, vous devez le faire vivre dans sa propre structure de données. Et si un parent existe, il suffit de les lier en ajoutant une référence de l'objet dans le parent.

Je ne sais pas vraiment quelle est la différence entre les deux relations? Voici un lien les expliquant: Agrégation vs Composition en UML

1
Bonjour123