MongoDBでリレーションシップを作成するには、BSONドキュメントを別のドキュメントに埋め込むか、別のドキュメントから参照します。
MongoDBデータベースは、リレーショナルデータベースとは動作が異なります。これは関係にも当てはまります。
MongoDBでは、次の2つの方法のいずれかを使用してリレーションシップを作成できます。
- 埋め込まれたドキュメント。
- 参照ドキュメント。
使用する方法は、データと、そのデータをクエリする方法によって異なります。
埋め込まれた関係
MongoDBを使用すると、ドキュメントをドキュメント内に埋め込むことができます。したがって、1つのドキュメントに独自の関係を含めることができます。
実際、最初にドキュメントを作成したときに、このメソッドを使用してすでにリレーションシップを作成しました。
1対1の関係
1対1の関係 親ドキュメントに1つの子があり、子に1つの親がある場所です。
たとえば、ビジネスルールでは、アーティストが持つことができるアドレスは1つだけであり、アドレスは1人のアーティストにしか属することができないと規定されている場合があります。
次のコードは、ドキュメント内に埋め込まれた1対1の関係を作成します。
db.artists.insert( { _id : 2, artistname : "Prince", address : { street : "Audubon Road", city : "Chanhassen", state : "Minnesota", country : "United States" } } )
結果:
WriteResult({ "nInserted" : 1 })
1対多の関係
1対多 関係とは、親ドキュメントが多くの子ドキュメントを持つことができるが、子ドキュメントが持つことができる親ドキュメントは1つだけである場合です。
したがって、別のビジネスルールでは、1人のアーティストが多数のアルバムを持つことができますが、アルバムは1人のアーティストにしか属することができないと言う場合があります。
次のコードを実行すると、1対多の関係が作成されます。
db.artists.insert( { _id : 3, artistname : "Moby", albums : [ { album : "Play", year : 1999, genre : "Electronica" }, { album : "Long Ambients 1: Calm. Sleep.", year : 2016, genre : "Ambient" } ] } )
結果:
WriteResult({ "nInserted" : 1 })
ドキュメント参照関係
ドキュメント参照を使用して、関係を作成できます。 (上記のように)子ドキュメントを親ドキュメントに埋め込むのではなく、子ドキュメントを独自のスタンドアロンドキュメントに分離します。
だから私たちはこれを行うことができます:
親ドキュメント
db.artists.insert( { _id : 4, artistname : "Rush" } )
子ドキュメント
バンドメンバーごとに1つずつ、合計3つの子ドキュメントを挿入します。
db.musicians.insert( { _id : 9, name : "Geddy Lee", instrument : [ "Bass", "Vocals", "Keyboards" ], artist_id : 4 } )
db.musicians.insert( { _id : 10, name : "Alex Lifeson", instrument : [ "Guitar", "Backing Vocals" ], artist_id : 4 } )
db.musicians.insert( { _id : 11, name : "Neil Peart", instrument : "Drums", artist_id : 4 } )
関係のクエリ
上記の2つのドキュメントを挿入した後、$lookup
を使用できます。 2つのコレクションで左外部結合を実行します。
これは、aggregate()
と組み合わせて使用します メソッド、および$match
興味のある特定のアーティストを指定するには、親と子のドキュメントを1つに返します。
db.artists.aggregate([ { $lookup: { from: "musicians", localField: "_id", foreignField: "artist_id", as: "band_members" } }, { $match : { artistname : "Rush" } } ]).pretty()
結果:
{ "_id" : 4, "artistname" : "Rush", "band_members" : [ { "_id" : 9, "name" : "Geddy Lee", "instrument" : [ "Bass", "Vocals", "Keyboards" ], "artist_id" : 4 }, { "_id" : 10, "name" : "Alex Lifeson", "instrument" : [ "Guitar", "Backing Vocals" ], "artist_id" : 4 }, { "_id" : 11, "name" : "Neil Peart", "instrument" : "Drums", "artist_id" : 4 } ] }
最初の2つのフィールドはアーティストコレクションからのものであり、残りはミュージシャンコレクションからのものであることがわかります。
したがって、アーティストコレクションのみをクエリする場合:
db.artists.find( { artistname : "Rush" } )
あなたはこれだけを得るでしょう:
{ "_id" : 4, "artistname" : "Rush" }
関連するデータは返されません。
埋め込みドキュメントと参照ドキュメントを使用する場合
関係を作成する両方の方法には、長所と短所があります。埋め込みドキュメントを使用する場合もあれば、参照ドキュメントを使用する場合もあります。
埋め込み関係を使用する場合
埋め込み関係方式を使用する主な利点の1つは、パフォーマンスです。リレーションシップがドキュメント内に埋め込まれている場合、クエリは複数のドキュメントに分散している場合よりも高速に実行されます。 MongoDBは、関係を取得するために複数のドキュメントを結合するのではなく、1つのドキュメントを返すだけで済みます。これにより、特に大量のデータを処理する場合に、パフォーマンスが大幅に向上します。
埋め込まれた関係により、クエリの記述も容易になります。一意の識別子を介して多くのドキュメントを結合する複雑なクエリを作成するのではなく、1つのクエリ内ですべての関連データを返すことができます。
覚えておくべきもう1つの考慮事項は、MongoDBはドキュメントレベルでのみ原子性を保証できるということです。単一のドキュメントに対するドキュメントの更新は常にアトミックですが、複数のドキュメントに対する更新ではありません。
複数のユーザーがデータにアクセスしている場合、2人以上のユーザーが同じドキュメントを異なるデータで更新しようとする可能性が常にあります。この場合、MongoDBは競合が発生せず、一度に1セットのデータのみが更新されることを保証します。 MongoDBは、複数のドキュメントにわたってこれを保証することはできません。
したがって、一般に、ドキュメントがサイズ制限(書き込み時点で16メガバイト)および/またはそのネスト制限(書き込み時点で100レベルの深さ)内にある限り、埋め込み関係を使用できます。
ただし、埋め込まれた関係はすべてに適しているわけではありません 機会。ドキュメント参照関係を作成する方が理にかなっている場合があります。
参照関係を使用する場合
多くのドキュメントで繰り返す必要のあるデータの場合、それらを独自の個別のドキュメントに含めると役立つ場合があります。これにより、エラーが減り、データの一貫性を保つのに役立ちます(複数のドキュメントの更新はアトミックではないことに注意してください)。
上記の例を使用すると、1人のミュージシャンが多くのバンドのメンバー(または元メンバー)になることができます。他のアーティストのアルバムを制作したり、学生に教えたり、診療所を運営したりする人もいます。また、各ミュージシャンに対して多くのデータを保存することもできます。したがって、この場合、ミュージシャンごとに個別のドキュメントを用意することは理にかなっています。
また、埋め込まれたドキュメントがMongoDBによって課せられたファイルサイズの制限を超える可能性があると思われる場合は、一部のデータを別のドキュメントに保存する必要があります。