Docs Menu
Docs Home
/
MongoDB マニュアル
/ /

無制限の配列を避ける

項目一覧

  • サブセット パターン
  • 参照データ
  • $lookup を使用した配列フィールドでの結合
  • 詳細

配列をフィールド値として保存すると、データを埋め込み、まとめてアクセスされるデータをまとめて保存できます。ただし、配列の要素数を制限しないと、ドキュメントが 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,
}
] )

booksreviewsの情報が別々のコレクションに保存されている場合、アプリケーションは$lookup操作を実行してデータを結合する必要があります。

booksreviews次の集計操作は、前の例の コレクションと コレクションを結合します。

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ドキュメントには結合されたデータが保存されます。

戻る

スキーマ設計のアンチパターン