私は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
はその質問を見つけさせません。 (私は初心者なので、_id
とquestion_ref
なしでこれを行う方法があるかどうかわかりません。)
ref
ではなくembed
を使用する必要がありますか?次に、コメント用の新しいコレクションを作成する必要がありますか?
これは科学よりも芸術です。スキーマに関する Mongoドキュメント は良い参考文献ですが、ここで考慮すべき点がいくつかあります。
できるだけ多く入れる
ドキュメントデータベースの喜びは、たくさんの結合を排除することです。あなたの最初の本能はあなたができる限り一つの文書にできるだけ多くを置くことであるべきです。 MongoDBドキュメントは構造を持ち、その構造内で効率的にクエリを実行できるので(つまり、必要なドキュメントの一部を使用できるので、ドキュメントのサイズを気にする必要はありません)、すぐにデータを正規化する必要はありません。あなたはSQLになります。特に、その親文書とは別に有用ではないデータは、同じ文書の一部であるべきです。
参照できるデータを複数の場所から独自のコレクションに分けます。
これは「データの一貫性」の問題であるため、「記憶領域」の問題ではありません。多くのレコードが同じデータを参照する場合は、単一のレコードを更新して他の場所でそのレコードを参照し続ける方が効率的でエラーが少なくなります。
文書サイズの考慮事項
MongoDBは1つのドキュメントに4MB(1.8MBで16MB)のサイズ制限を課します。 GBのデータの世界ではこれは小さいように思えますが、それはまた3万ツイートまたは250の典型的なStack Overflowの回答または20のちらつきの写真です。一方、これは典型的なWebページに一度に表示したいものよりはるかに多くの情報です。まず、クエリを簡単にするものを検討してください。多くの場合、ドキュメントサイズに関する懸念は時期尚早の最適化になります。
複雑なデータ構造
MongoDBは任意の深いネストしたデータ構造を保存できますが、効率的に検索することはできません。データがツリー、フォレスト、またはグラフを形成している場合は、各ノードとそのエッジを別々のドキュメントに格納する必要があります。 (このタイプのデータ用に特別に設計されたデータストアもありますので注意してください)
ドキュメント内の要素のサブセットを返すことが不可能であるということよりも、 も指摘されています 。各文書のうちのいくつかを選んで選択する必要がある場合は、それらを分離する方が簡単です。
データの一貫性
MongoDBは効率と一貫性の間でトレードオフを作ります。 1つの文書への変更は常にアトミックアトミックであるのに対して、複数の文書への更新はアトミックと見なされるべきではありません。サーバー上のレコードを「ロック」する方法もありません(たとえば、「lock」フィールドを使用してこれをクライアントのロジックに組み込むことができます)。スキーマを設計するときは、データの一貫性をどのように維持するかを検討してください。一般的には、文書に保存する量が多いほど優れています。
あなたが説明していることのために、私はコメントを埋め込み、そして各コメントにObjectIDを持つidフィールドを与えます。 ObjectIDにはタイムスタンプが埋め込まれているので、必要に応じてで作成した代わりにそれを使用できます。
特定のコメントを編集したい場合、その内容と質問を取得する方法
サブドキュメントdb.question.find({'comments.content' : 'xxx'})
で問い合わせることができます。
これは質問文書全体を返します。指定されたコメントを編集するには、クライアント上でコメントを見つけて編集し、それをDBに保存し直す必要があります。
一般に、ドキュメントにオブジェクトの配列が含まれている場合は、それらのサブオブジェクトをクライアント側で変更する必要があることがわかります。
一般に、エンティティ間に1対1または1対多の関係がある場合は埋め込みが適しています。多対多の関係がある場合は参照が適しています。
私は少し遅れていますが、それでも私のスキーマ作成方法を共有したいと思います。
古典的なOOPで行うのと同じように、Wordで記述できるすべてのスキーマを用意しています。
例えば。
すべてのスキーマはDocumentまたはSubdocumentとして保存できるので、これを各スキーマに対して宣言します。
資料:
サブドキュメント:
私はこれはかなり古いことを知っていますが、指定されたコメントだけを返す方法についてのOPの質問に対する答えを探しているなら、あなたはこのように $(query) 演算子を使うことができます。
db.question.update({'comments.content': 'xxx'}, {'comments.$': true})
私は自分自身でこの質問を調査しながらこの小さなプレゼンテーションに出会いました。私はそれがどのようにうまくレイアウトされているか、その情報とプレゼンテーションの両方に驚きました。
http://openmymind.net/Multiple-Collections-Versus-Embedded-Documents
それは要約しました:
原則として、たくさんの[子文書]がある場合、またはそれらが大きい場合は、個別のコレクションが最善です。
文書が小さければ少ないほど、埋め込むのに適しています。
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
実は、なぜUML仕様について誰も話さなかったのは私が非常に興味を持っています。経験則として、集約がある場合は、参照を使用するべきです。しかし、それがコンポジションであれば、結合はより強くなるので、埋め込み文書を使うべきです。
そして、あなたはすぐにそれが論理的である理由を理解するでしょう。オブジェクトが親から独立して存在できる場合は、親が存在しなくてもアクセスする必要があります。存在しない親に埋め込むことはできないので、それを独自のデータ構造内に存在させる必要があります。そして親が存在する場合は、単に親の中にオブジェクトの参照を追加することによってそれらを一緒にリンクします。
この2つの関係の違いは本当にわかりませんか?これを説明するリンクは次のとおりです。 UMLでの集約と構成
このクイズは、どちらを使用するべきかを判断するための参考として作成しました。