無制限の配列を避ける
配列をフィールド値として保存すると、データを埋め込み、まとめてアクセスされるデータをまとめて保存できます。 ただし、配列の要素数を制限しないと、ドキュメントが 16 MB のBSONドキュメントサイズ制限 を超える可能性があります。 無制限配列は、アプリケーションのリソースに負担がかかり、インデックスのパフォーマンスを低下させる可能性があります。
データセット全体を埋め込む代わりに、サブ設定と境界のある配列への参照を使用することで、パフォーマンスが向上し、管理しやすいドキュメントサイズを維持できます。 データをサブセットするときは、操作するデータの必要な部分のみを選択するため、関連するデータのみに集中することでメモリ使用量と処理時間が削減されます。 データを参照する場合は、ドキュメントに直接埋め込むのではなく、外部データソースにリンクします。 このアプローチにより、パフォーマンスが向上し、ドキュメントサイズが縮小されます。 サブ設定と参照を使用すると、配列を制限し、日付をより効率的に管理できます。
例
映画館アプリケーションの書籍レビューを追跡する次のスキーマを考えてみましょう。 初期スキーマでは、 reviews
フィールドに配列が使用されます。
{ title: "Harry Potter", author: "J.K. Rowling", publisher: "Scholastic", reviews: [ { user: "Alice", review: "Great book!", rating: 5 }, { user: "Bob", review: "Didn't like it!", rating: 1 }, { user: "Charlie", review: "Not bad, but could be better.", rating: 3 } ] }
このスキーマでは、 reviews
フィールドは 無制限配列 です。 この書籍に対して新しいレビューが作成されるたびに、アプリケーションは新しいサブドキュメントをreviews
配列に追加します。 レビューを追加すると、 配列が大きくなりすぎて、アプリケーションのリソースに負担がかかります。
この例では 、出版社アプリケーションは 1 冊の書籍につき 3 つの書籍レビューを表示するだけで済みます。 無制限配列を回避するには、ユースケースに応じて、サブセット 設計パターンまたはドキュメント参照を使用できます。
サブセット パターン
データをサブ設定することは、頻繁にアップデートされないデータにすばやくアクセスする必要がある場合に最適です。 サブセット パターンを使用すると、書籍のドキュメントに 3 つのレビューを埋め込むと、1 回の操作ですべての必要な情報を返すことができます。 その他のレビューは別のreviews
コレクションに保存されます。 このスキーマ設計パターンには、次の利点があります。
無制限配列の削除
ドキュメントサイズを制御する
複数のクエリの使用を避ける
books
コレクション:
db.books.insertOne( [ { title: "Harry Potter", author: "J.K. Rowling", publisher: "Scholastic", reviews: [ { reviewer: "Alice", review: "Great book!", rating: 5 }, { reviewer: "Charlie", review: "Didn't like it.", rating: 1 }, { reviewer: "Bob", review: "Not bad, but could be better.", rating: 3 } ], } ] )
reviews
コレクション:
db.reviews.insertMany( [ { reviewer: "Jason", review: "Did not enjoy!", rating: 1 }, { reviewer: "Pam", review: "Favorite book!", rating: 5 }, { reviewer: "Bob", review: "Not bad, but could be better.", rating: 3 } ] )
このアプローチではデータが重複するため、更新コストが高くなります。 レビューが頻繁に更新されない場合は、このアプローチが最適です。
参照データ
データ参照は、大規模なデータセットまたは頻繁にアップデートされるデータセットをドキュメントサイズを使用して管理する必要がある場合に最適です。
データを参照するには、レビューを別のコレクションに保存し、 reviews
コレクション内のドキュメントにreview_id
フィールドを追加します。 books
コレクション内のレビューを参照するには、 review_id
フィールドを使用します。
このアプローチは無制限配列の問題を解決しますが、 books
コレクションのレビュー情報を取得するにはreviews
コレクションをクエリする必要があるため、レイテンシが発生します。 ユースケースによっては、この追加のレイテンシは無制限の配列によって発生する問題を回避するために許容できるトレードオフになる場合があります。
books
コレクション:
db.books.insertMany( [ { title: "Harry Potter", author: "J.K. Rowling", publisher: "Scholastic", reviews: ["review1", "review2", "review3"] }, { title: "Pride and Prejudice", author: "Jane Austen", publisher: "Penguin", reviews: ["review4", "review5"] } ] )
reviews
コレクション:
db.reviews.insertMany( [ { review_id: "review1", reviewer: "Jason", review: "Did not enjoy!", rating: 1 }, { review_id: "review2", reviewer: "Pam", review: "Favorite book!", rating: 5 }, { review_id: "review3", reviewer: "Bob", review: "Not bad, but could be better.", rating: 3 }, { review_id: "review4", reviewer: "Tina", review: "Amazing!", rating: 5 }, { review_id: "review5", reviewer: "Jacob", review: "A little overrated", rating: 4, } ] )
$lookup を使用した配列フィールドでの結合
books
とreviews
の情報が別々のコレクションに保存されている場合、アプリケーションは$lookup
操作を実行してデータを結合する必要があります。
books
reviews
次の集計操作は、前の例の コレクションと コレクションを結合します。
db.books.aggregate( [ { $lookup: { from: "reviews", localField: "reviews", foreignField: "review_id", as: "reviewDetails" } } ] )
この操作では、以下を返します。
[ { _id: ObjectId('665de81eeda086b5e22dbcc9'), title: 'Harry Potter', author: 'J.K. Rowling', publisher: 'Scholastic', reviews: [ 'review1', 'review2', 'review3' ], reviewDetails: [ { _id: ObjectId('665de82beda086b5e22dbccb'), review_id: 'review1', reviewer: 'Jason', review: 'Did not enjoy!', rating: 1 }, { _id: ObjectId('665de82beda086b5e22dbccc'), review_id: 'review2', reviewer: 'Pam', review: 'Favorite book!', rating: 5 }, { _id: ObjectId('665de82beda086b5e22dbccd'), review_id: 'review3', reviewer: 'Bob', review: 'Not bad, but could be better.', rating: 3 } ] }, { _id: ObjectId('665de81eeda086b5e22dbcca'), title: 'Pride and Prejudice', author: 'Jane Austen', publisher: 'Penguin', reviews: [ 'review4', 'review5' ], reviewDetails: [ { _id: ObjectId('665de82beda086b5e22dbcce'), review_id: 'review4', reviewer: 'Tina', review: 'Amazing!', rating: 5 }, { _id: ObjectId('665de82beda086b5e22dbccf'), review_id: 'review5', reviewer: 'Jacob', review: 'A little overrated', rating: 4 } ] } ]
この例では 、 $lookup
操作は、書籍ドキュメントのreviews
配列とレビュー ドキュメントのreview_id
フィールドを使用して、 books
コレクションとreviews
コレクションを結合します。 reviewDetails
ドキュメントには結合されたデータが保存されます。