web-dev-qa-db-ja.com

MongoDB関係:埋め込みまたは参照?

私はMongoDBが初めてです。リレーショナルデータベースのバックグラウンドから来ています。コメント付きの質問構造を設計したいのですが、コメントに使用する関係がわかりません:embedまたはreference

stackoverflow のようなコメント付きの質問には、次のような構造があります。

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

最初は、次のように埋め込みコメント(MongoDBではembedが推奨されると思います)を使用します。

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

それは明らかですが、私はこのケースについて心配しています:指定されたコメントを編集したい場合、その内容と質問を取得するにはどうすればよいですか?_idは私にそれを見つけさせ、_question_refはその質問を見つけさせません。 (私は初心者なので、_idquestion_refなしでこれを行う方法があるかどうかわかりません。)

refではなくembedを使用する必要がありますか?次に、コメント用の新しいコレクションを作成する必要がありますか?

476
Freewind

これは科学よりも芸術です。スキーマに関する Mongoドキュメント は良い参考文献ですが、ここで考慮すべき点がいくつかあります。

  • できるだけ多く入れる

    ドキュメントデータベースの喜びは、たくさんの結合を排除することです。あなたの最初の本能はあなたができる限り一つの文書にできるだけ多くを置くことであるべきです。 MongoDBドキュメントは構造を持ち、その構造内で効率的にクエリを実行できるので(つまり、必要なドキュメントの一部を使用できるので、ドキュメントのサイズを気にする必要はありません)、すぐにデータを正規化する必要はありません。あなたはSQLになります。特に、その親文書とは別に有用ではないデータは、同じ文書の一部であるべきです。

  • 参照できるデータを複数の場所から独自のコレクションに分けます。

    これは「データの一貫性」の問題であるため、「記憶領域」の問題ではありません。多くのレコードが同じデータを参照する場合は、単一のレコードを更新して他の場所でそのレコードを参照し続ける方が効率的でエラーが少なくなります。

  • 文書サイズの考慮事項

    MongoDBは1つのドキュメントに4MB(1.8MBで16MB)のサイズ制限を課します。 GBのデータの世界ではこれは小さいように思えますが、それはまた3万ツイートまたは250の典型的なStack Overflowの回答または20のちらつきの写真です。一方、これは典型的なWebページに一度に表示したいものよりはるかに多くの情報です。まず、クエリを簡単にするものを検討してください。多くの場合、ドキュメントサイズに関する懸念は時期尚早の最適化になります。

  • 複雑なデータ構造

    MongoDBは任意の深いネストしたデータ構造を保存できますが、効率的に検索することはできません。データがツリー、フォレスト、またはグラフを形成している場合は、各ノードとそのエッジを別々のドキュメントに格納する必要があります。 (このタイプのデータ用に特別に設計されたデータストアもありますので注意してください)

    ドキュメント内の要素のサブセットを返すことが不可能であるということよりも、 も指摘されています 。各文書のうちのいくつかを選んで選択する必要がある場合は、それらを分離する方が簡単です。

  • データの一貫性

    MongoDBは効率と一貫性の間でトレードオフを作ります。 1つの文書への変更は常にアトミックアトミックであるのに対して、複数の文書への更新はアトミックと見なされるべきではありません。サーバー上のレコードを「ロック」する方法もありません(たとえば、「lock」フィールドを使用してこれをクライアントのロジックに組み込むことができます)。スキーマを設計するときは、データの一貫性をどのように維持するかを検討してください。一般的には、文書に保存する量が多いほど優れています。

あなたが説明していることのために、私はコメントを埋め込み、そして各コメントにObjectIDを持つidフィールドを与えます。 ObjectIDにはタイムスタンプが埋め込まれているので、必要に応じてで作成した代わりにそれを使用できます。

711
John F. Miller

特定のコメントを編集したい場合、その内容と質問を取得する方法

サブドキュメントdb.question.find({'comments.content' : 'xxx'})で問い合わせることができます。

これは質問文書全体を返します。指定されたコメントを編集するには、クライアント上でコメントを見つけて編集し、それをDBに保存し直す必要があります。

一般に、ドキュメントにオブジェクトの配列が含まれている場合は、それらのサブオブジェクトをクライアント側で変更する必要があることがわかります。

32
Gates VP

一般に、エンティティ間に1対1または1対多の関係がある場合は埋め込みが適しています。多対多の関係がある場合は参照が適しています。

30
ywang1724

私は少し遅れていますが、それでも私のスキーマ作成方法を共有したいと思います。

古典的なOOPで行うのと同じように、Wordで記述できるすべてのスキーマを用意しています。

例えば。

  • コメント
  • アカウント
  • ユーザー
  • ブログ投稿
  • ...

すべてのスキーマはDocumentまたはSubdocumentとして保存できるので、これを各スキーマに対して宣言します。

資料:

  • 参考として使用することができます。 (例えば、ユーザがコメントをした - >コメントは、ユーザへの「によって作成された」参照を有する)
  • あなたのアプリケーションの「ルート」です。 (例えばブログ投稿 - >ブログ投稿についてのページがあります)

サブドキュメント:

  • 一度だけ使用できます/参照することはできません。 (例:コメントはブログ投稿に保存されます)
  • あなたのアプリケーションでは決して「ルート」ではありません。 (コメントはブログ投稿ページに表示されるだけですが、そのページはまだブログ投稿に関するものです)
19
Silom

私はこれはかなり古いことを知っていますが、指定されたコメントだけを返す方法についてのOPの質問に対する答えを探しているなら、あなたはこのように $(query) 演算子を使うことができます。

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

私は自分自身でこの質問を調査しながらこの小さなプレゼンテーションに出会いました。私はそれがどのようにうまくレイアウトされているか、その情報とプレゼンテーションの両方に驚きました。

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

それは要約しました:

原則として、たくさんの[子文書]がある場合、またはそれらが大きい場合は、個別のコレクションが最善です。

文書が小さければ少ないほど、埋め込むのに適しています。

17
Chris Bloom

Sql i joinのように他のドキュメントにデータを追加することもできます。Mongodbでは、1対多の関係ドキュメントをマッピングすることには参加できません。代わりに、 populate を使用して実行できます。シナリオ..

var mongoose = require('mongoose')
  , Schema = mongoose.Schema

var personSchema = Schema({
  _id     : Number,
  name    : String,
  age     : Number,
  stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

var storySchema = Schema({
  _creator : { type: Number, ref: 'Person' },
  title    : String,
  fans     : [{ type: Number, ref: 'Person' }]
});

ポピュレーションは、ドキュメント内の指定されたパスを他のコレクションからのドキュメントと自動的に置き換えるプロセスです。単一のドキュメント、複数のドキュメント、プレーンオブジェクト、複数のプレーンオブジェクト、またはクエリから返されたすべてのオブジェクトを設定できます。いくつかの例を見てみましょう。

より多くの情報を得ることができるようになった方がよいです。 http://mongoosejs.com/docs/populate.html

10
Narendran

指定したコメントを編集したい場合、その内容と質問をどのようにして入手できますか?

あなたがコメントの数とあなたが変更したいコメントのインデックスを追跡していたならば、あなたは ドット演算子SOの例 )。

あなたはf.ex.をすることができます.

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

(質問内のコメントを編集する別の方法として)

1
serv-inc

実は、なぜUML仕様について誰も話さなかったのは私が非常に興味を持っています。経験則として、集約がある場合は、参照を使用するべきです。しかし、それがコンポジションであれば、結合はより強くなるので、埋め込み文書を使うべきです。

そして、あなたはすぐにそれが論理的である理由を理解するでしょう。オブジェクトが親から独立して存在できる場合は、親が存在しなくてもアクセスする必要があります。存在しない親に埋め込むことはできないので、それを独自のデータ構造内に存在させる必要があります。そして親が存在する場合は、単に親の中にオブジェクトの参照を追加することによってそれらを一緒にリンクします。

この2つの関係の違いは本当にわかりませんか?これを説明するリンクは次のとおりです。 UMLでの集約と構成

1
Bonjour123

このクイズは、どちらを使用するべきかを判断するための参考として作成しました。

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

0
Emmanuel Orozco