属性パターンは、特にフィールドが共通の特徴を持つ場合に、多数の類似フィールドを持つドキュメントを整理するスキーマ設計パターンです。類似フィールドのこれらのサブセットに対してソートまたはクエリを実行する必要がある場合は、属性パターンによってスキーマを最適化 できます。ドキュメントごとの複数の類似フィールドをキー値のサブドキュメントに統合することで、ドキュメントのインデックス作成が容易になります。属性パターンによって複数の類似フィールドに複数のインデックスを作成する代わりに、作成数を少なくできるため、クエリの高速化と書込みが容易になります。
コレクションに次の条件のいずれかに当てはまる場合は、 属性パターンを使用します。
ソートまたはクエリを実行したい共有特徴を持つ多数の類似フィールドを含む大きなドキュメントがある。
ドキュメントの小さなサブセットには、ソートに必要なフィールドが含まれています。
このタスクについて
映画のコレクションを検討します。コレクション内の一般的なドキュメントは次のようになります。
db.movies.insertOne( { "_id": 1, "title": "Star Wars", "runtime": 121, "directors": ["George Lucas"], release_US: ISODate("1977-05-20T01:00:00+01:00"), release_France: ISODate("1977-10-19T01:00:00+01:00"), release_Italy: ISODate("1977-10-20T01:00:00+01:00"), release_UK: ISODate("1977-12-27T01:00:00+01:00") } )
上記のドキュメントには、複数の国のリリース日フィールドに注意してください。リリース日を検索する場合は、多くのフィールドを一度に調べる必要があります。属性パターンがない場合、リリース日の検索をすばやく実行するには、movies
コレクションにいくつかのインデックスを作成する必要があります。
db.movies.createIndex({ release_US: 1 }); db.movies.createIndex({ release_France: 1 }); db.movies.createIndex({ release_Italy: 1 }); db.movies.createIndex({ release_UK: 1 });
ただし、インデックスは高価であり、特に書込み操作のパフォーマンスを低下させる可能性があります。次の手順では、さまざまなリリース日の情報サブセットを配列に移動して、インデックスの必要性を減らすことで、movies
コレクションに属性パターンを適用する方法を示しています。
手順
データのサブセットを 1 つの配列にグループ化します。
スキーマを再構成して、さまざまなリリース日フィールドをキーと値のペアの配列にします。
db.movies.insertOne( { "_id": 1, "title": "Star Wars", "runtime": 121, "directors": ["George Lucas"], releases: [ { location: "USA", date: ISODate("1977-05-20T01:00:00+01:00") }, { location: "France", date: ISODate("1977-10-19T01:00:00+01:00") }, { location: "Italy", date: ISODate("1977-10-20T01:00:00+01:00") }, { location: "UK", date: ISODate("1977-12-27T01:00:00+01:00") } ] } )
結果
ドキュメントに同じ特性または類似の特性を追跡する複数のフィールドがある場合、属性パターンによって類似するフィールドごとにインデックスを作成する必要がなくなります。同様のフィールドを配列に統合し、その配列にインデックスを作成することで、必要なインデックスの総数を減らし、クエリのパフォーマンスを向上させます。
その他のユースケース
属性パターンは、ドキュメントがアイテムの特性を説明する場合に役立ちます。衣料品などの一部の製品のサイズは、小、中、または大で表示される場合があります。同じコレクション内の他の製品はボリュームで表される場合もありますが、他の製品は物理的単位または重みで表される場合があります。
例、 の下のボトルネックのコレクションを考えてみましょう。属性パターンを使用しないドキュメントは次のようになります。
db.bottles.insertOne([ { "_id": 1, "volume_ml": 500, "volume_ounces": 12 } ])
次のコードでは、属性パターン を bottles
コレクションに適用します。
db.bottles.insertOne([ { "_id": 1, specs: [ { k: "volume", v: "500", u: "ml" }, { k: "volume", v: "12", u: "ounces" }, ] } ])
最初のドキュメントの volume_ml
フィールドと volume_ounces
フィールドには同様の情報が含まれているため、上記のスキーマはそれらを 1 つのフィールドspecs
に統合します。specs
フィールドは、特定のサーバーの測定仕様に関する情報をグループ化します。k
フィールドは測定対象を指定し、v
は値を指定し、u
は測定単位を指定します。
属性パターンを使用すると、異なる名前を持つ類似フィールドをグループ化することもできます。測定対象を指定する k
フィールド のように、キーと値のペアで属性を指定することで、より幅広い類似フィールドを 1 つの配列に保存でき、データを効率的にクエリするために必要なインデックスの数を最小限に抑えることができます。
例、属性パターンを使用していない bottles
コレクション内の次のドキュメントを考えてみましょう。このドキュメントには、サーバー用の容量と高さの仕様が保存されています。
db.bottles.insertOne([ { "_id": 1, "volume_ml": 500, "volume_ounces": 12, "height_inches": 8 } ])
次のコードは、ドキュメントに属性パターン を適用します。volume_ml
、volume_ounces
、height_inches
フィールドはすべて specs
配列にグループ化されます。
db.bottles.insertOne([ { "_id": 1, specs: [ { k: "volume", v: "500", u: "ml" }, { k: "volume", v: "12", u: "ounces" }, { k: "height", v: "8", u: "inches" } ] } ])
k
、v
、u
などのキーと値のペアを使用すると、配列に追加できるフィールドの柔軟性が向上します。配列に連結できるフィールドが多いほど、作成する必要があるインデックスが少なくなり、クエリのパフォーマンスが最大化されます。