Multikey Indexes
配列値を持つフィールドにインデックスを付けるために、MongoDB は配列内の一意の要素ごとにインデックス キーを作成します。 これらのマルチキーインデックスは、配列フィールドに対する効率的なクエリをサポートします。 マルチキー インデックスは、両方のスカラー値[1] を含む配列に対して構築できます [1] (例: 文字列、数値)やネストされたドキュメントをサポートします。 配列に同じ値のインスタンスが複数含まれている場合、インデックスには値のエントリが 1 つだけ含まれます。
[1] | スカラー値とは、埋め込みドキュメントでも配列でもない値を指します。 |
互換性
MongoDB Atlas でホストされている配置ではマルチキー インデックスを使用できます。
MongoDB Atlas でホストされている配置のインデックスの管理の詳細については、「インデックスの作成、表示、削除、および非表示 」を参照してください。
マルチキー インデックスの作成
マルチキー インデックスを作成するには、 db.collection.createIndex()
メソッドを使用します。
db.coll.createIndex( { <field>: < 1 or -1 > } )
MongoDB は、インデックス フィールドが配列である場合、マルチキー インデックスを自動的に作成します。マルチキーのタイプを明示的に指定する必要はありません。
注意
WiredTiger および インメモリ ストレージ エンジン のみ、
マルチキー インデックスの場合、MongoDB は、どのインデックス付きフィールドがインデックスをマルチキー インデックスにするかを追跡します。 この情報を追跡することで、MongoDB クエリ エンジンはより厳しいインデックス限界を使用できるようになります。
インデックスの限界
インデックスがマルチキーの場合、インデックスの限界の計算は特別なルールに従います。 マルチキー インデックスの限界の詳細については、「 マルチキー インデックスの限界 」を参照してください。
一意のマルチキー インデックス
一意なインデックスの場合、一意の制約は単一のドキュメント内ではなく、コレクション内の個別のドキュメント全体に適用されます。
この制約は個別のドキュメントに適用されるため、一意の マルチキー インデックスの場合、ドキュメントに含まれる配列要素によって、そのドキュメントのインデックス キー値と別のドキュメントのインデックス キー値が重複していない限り、インデックス キー値の反復につながることがあります。
詳細については、「 複数の別個のドキュメント間で一意の制約 」を参照してください。
制限
複合マルチキー インデックス
複合マルチキー インデックスの場合、インデックス作成されたそれぞれのドキュメントには、値が配列であるインデックス付きフィールドを最大で1 つ含めることができます。 つまり、
ドキュメント内のインデックスを作成するフィールドの複数が配列の場合、複合マルチキー インデックスを作成することはできません。 たとえば、次のドキュメントを含む コレクションを考えます。
{ _id: 1, a: [ 1, 2 ], b: [ 1, 2 ], category: "AB - both arrays" } コレクションに複合マルチキー インデックス
{ a: 1, b: 1 }
a
b
を作成することはできません。 フィールドと フィールドは両方とも配列であるためです。または、複合マルチキー インデックスがすでに存在する場合、この制限に違反するドキュメントを挿入することはできません。
以下のドキュメントを含むコレクション を考慮します:
{ _id: 1, a: [1, 2], b: 1, category: "A array" } { _id: 2, a: 1, b: [1, 2], category: "B array" } 複合マルチキー インデックス
{ a: 1, b: 1 }
は、各ドキュメントで、複合マルチキー インデックスでインデックス付けされた 1a
b
つのフィールドのみが配列であるため、許可されます。つまり、 フィールドと フィールドの両方の配列値を含むドキュメントはありません。ただし、複合マルチキー インデックスの作成後に、
a
b
フィールドと フィールドの両方が配列であるドキュメントを挿入しようとすると、MongoDB は挿入を失敗します。
フィールドがドキュメントの配列である場合は、埋め込みフィールドにインデックスを付けて複合インデックスを作成できます。 たとえば、次のドキュメントを含むコレクションで考えてみましょう。
{ _id: 1, a: [ { x: 5, z: [ 1, 2 ] }, { z: [ 1, 2 ] } ] } { _id: 2, a: [ { x: 5 }, { z: 4 } ] }
{ "a.x": 1, "a.z": 1 }
で複合インデックスを作成できます。 最大1 つのインデックス付きフィールドが配列であるという制限も適用されます。
ソート
MongoDB 4.4の配列フィールドのソート動作が変更された結果として、マルチキー インデックスでインデックス付けされた配列でソートする場合、次の場合を除き、クエリプランにはブロッキングソートステージが含まれます。
すべてのソートフィールドのインデックスの限界は
[MinKey, MaxKey]
で、かつマルチキー インデックスの付いたフィールドの境界には、ソート パターンと同じパス プレフィックスはありません。
シャードキー
マルチキー インデックスをシャードキー インデックスとして指定することはできません。
ただし、 シャード キー インデックスが複合インデックスの プレフィックス である場合、他のキー(シャードキーの一部ではないキー)は、配列をインデックスします。 複合マルチキー インデックス はパフォーマンスに影響を与える可能性があります。
ハッシュされたインデックス
ハッシュされたインデックス をマルチキーにすることはできません。
カバード クエリ
次の条件が満たされている場合、マルチキー インデックスはクエリをカバーできます。
クエリは配列フィールドを返しません(つまり、配列はクエリプロジェクションに含まれていません)。つまり、クエリをカバーするには、マルチキーインデックスが複合である必要があることを意味します。
クエリには
$elemMatch
が含まれていません。このクエリは、対象となる他のすべてのクエリ要件を満たしています。
たとえば、以下のドキュメントのあるmatches
コレクションを考えます。
db.matches.insertMany( [ { name: "Joe", event: [ "open", "tournament" ] }, { name: "Bill", event: [ "match", "championship" ] } ] )
matches
コレクションでは、 event
フィールドとname
フィールドに複合マルチキー インデックスがあります。
db.matches.createIndex( { event: 1, name: 1 } )
上記のインデックスは、event
フィールドに配列値が含まれているため、マルチキーです。
インデックスは次のクエリをカバーします。
db.matches.find( { event: 'championship' }, { _id: 0, name: 1 } ) db.matches.find( { name: 'Bill', event: 'championship' }, { _id: 0, name: 1 } )
プロジェクションには event
配列フィールドが含まれているため、インデックスは次のクエリをカバーしていません。
db.matches.find( { event: 'championship' }, { _id: 0, event: 1 } )
配列フィールド全体に対するクエリ
クエリ フィルターで 配列全体の完全一致 が指定されている場合、MongoDB はマルチキー インデックスを使用してクエリ配列の 最初の 要素を検索できますが、マルチキー インデックス スキャンを使用して配列全体を検索することはできません。 代わりに、マルチキー インデックスを使用してクエリ配列の最初の要素を検索した後、MongoDB は関連するドキュメントを取得し、配列がクエリの配列と一致するドキュメントをフィルタリングします。
たとえば、次のドキュメントを含むinventory
コレクションを考えてみます。
{ _id: 5, type: "food", item: "aaa", ratings: [ 5, 8, 9 ] } { _id: 6, type: "food", item: "bbb", ratings: [ 5, 9 ] } { _id: 7, type: "food", item: "ccc", ratings: [ 9, 5, 8 ] } { _id: 8, type: "food", item: "ddd", ratings: [ 9, 5 ] } { _id: 9, type: "food", item: "eee", ratings: [ 5, 9, 5 ] }
コレクションでは、 ratings
フィールドにマルチキー インデックスがあります。
db.inventory.createIndex( { ratings: 1 } )
次のクエリは、 ratings
フィールドが配列[ 5, 9 ]
であるドキュメントを検索します。
db.inventory.find( { ratings: [ 5, 9 ] } )
MongoDB ではマルチキー インデックスを使用して、 ratings
配列内の任意の位置に5
を持つドキュメントを見つけることができます。次に、MongoDB でこれらのドキュメントが取得され、ratings
配列がクエリ配列 [ 5, 9 ]
と等しいドキュメントがフィルタリングされます。
$expr
$expr
では、 マルチキー インデックス はサポートされていません。
例
インデックスの基本配列
次のドキュメントを使用してsurvey
コレクションを作成します。
db.survey.insertOne( { _id: 1, item: "ABC", ratings: [ 2, 5, 9 ] } )
フィールドratings
にインデックスを作成します。
db.survey.createIndex( { ratings: 1 } )
ratings
フィールドには配列が含まれているため、 ratings
のインデックスはマルチキーです。 マルチキー インデックスには、それぞれが同じドキュメントを指している次の 3 つのインデックス キーが含まれています。
2
,5
と9
.
埋め込みドキュメントを含む配列のインデックス
ネストされたオブジェクトを含む配列フィールドにマルチキー インデックスを作成できます。
次の形式のドキュメントを含むinventory
コレクションを考えてみましょう。
{ _id: 1, item: "abc", stock: [ { size: "S", color: "red", quantity: 25 }, { size: "S", color: "blue", quantity: 10 }, { size: "M", color: "blue", quantity: 50 } ] } { _id: 2, item: "def", stock: [ { size: "S", color: "blue", quantity: 20 }, { size: "M", color: "blue", quantity: 5 }, { size: "M", color: "black", quantity: 10 }, { size: "L", color: "red", quantity: 2 } ] } { _id: 3, item: "ijk", stock: [ { size: "M", color: "blue", quantity: 15 }, { size: "L", color: "blue", quantity: 100 }, { size: "L", color: "red", quantity: 25 } ] } ...
次の操作では、 フィールドと フィールドにマルチキー インデックスが作成されます。stock.size
stock.quantity
db.inventory.createIndex( { "stock.size": 1, "stock.quantity": 1 } )
複合マルチキー インデックスは、次の例のように、インデックス付きフィールドの両方を含む述語と、インデックス プレフィックス"stock.size"
のみを含む述語を含むクエリをサポートできます。
db.inventory.find( { "stock.size": "M" } ) db.inventory.find( { "stock.size": "S", "stock.quantity": { $gt: 20 } } )
MongoDBでマルチキー インデックスの限界を組み合わせる方法の詳細については、「 マルチキー インデックスの限界 」を参照してください。 複合インデックスとプレフィックスの動作の詳細については、「複合インデックスとプレフィックス 」を参照してください。
複合マルチキー インデックスは、次の例のようなソート操作もサポートできます。
db.inventory.find( ).sort( { "stock.size": 1, "stock.quantity": 1 } ) db.inventory.find( { "stock.size": "M" } ).sort( { "stock.quantity": 1 } )
複合インデックスとソート操作の動作の詳細については、「クエリ結果をソートするためにインデックスを使用する 」を参照してください。