マルチキー インデックスは、配列値を含むフィールドからデータを収集してソートします。マルチキー インデックスにより、配列フィールドに対するクエリのパフォーマンスが向上します。
インデックスをマルチキーとして明示的に指定する必要はありません。配列値を含むフィールドにインデックスを作成すると、MongoDB では自動的にそのインデックスがマルチキー インデックスに設定されます。
配列内の個別の値ごとに、MongoDB はインデックス内に個別のエントリを作成し、各エントリは同じドキュメントを指します。その結果、1 つのドキュメントはマルチキー インデックスに複数のエントリを持つことができます。配列に同じ値のインスタンスが複数含まれている場合、インデックスには値のエントリが 1 つだけ含まれます。
MongoDB では、スカラー値(文字列や数値など)と埋め込みドキュメントの両方を含む配列に対してマルチキー インデックスを作成できます。
マルチキー インデックスを作成するには、次のプロトタイプを使用します。
db.<collection>.createIndex( { <arrayField>: <sortOrder> } )
この図は、addr.zip フィールドのマルチキー インデックスを示しています。
ユースケース
アプリケーションが配列値を含むフィールドを頻繁にクエリする場合は、マルチキー インデックスを使用するとクエリのパフォーマンスが向上します。
例、moviesコレクション内のドキュメントには、各映画に関連付けられたジャンルの配列である genresフィールドが含まれています。特定のジャンルを持つ映画を定期的にクエリします。たとえば、Drama と Action の両方の映画をすべて検索します。
genres フィールドにインデックスを作成すると、このクエリのパフォーマンスを向上させることができます。genres には配列値が含まれているため、MongoDB はインデックスをマルチキー インデックスとして格納します。
はじめる
マルチキー インデックスを作成するには、以下を参照してください。
詳細
このセクションでは、マルチキー インデックスの技術的詳細と制限について説明します。
このページの例では、sample_mflix データセット のデータを使用しています。自己管理型 MongoDB 配置にこのデータセットをロードする方法の詳細については、「サンプル データセットのロード」を参照してください。サンプル データベースに何らかの変更を加えた場合は、今ページの例を実行するには、データベースを削除して再作成する必要がある可能性があります。
マルチキーになるフィールドに対するクエリ
MongoDB 9.0 以降では、インデックスが作成されたフィールドがマルチキーフィールドになった状態でそのフィールドを参照するクエリが実行されると、クエリが QueryKilledError で失敗する可能性があります。インデックスが作成されたフィールドは、ドキュメントを挿入または更新してそのフィールドに配列値が含まれるようになると、マルチキーになります。
このエラーでクエリが失敗した場合は、挿入または更新操作が完了した後にクエリを再実行してください。
インデックスの限界
インデックス スキャンの限界は、クエリ中に検索するインデックスの部分を定義します。マルチキー インデックスの限界の計算は特別なルールに従います。詳細については、「マルチキー インデックスの限界」を参照してください。
Unique Multikey Indexes
ユニークなマルチキー インデックスでは、そのドキュメントのインデックスキー値が別のドキュメントのインデックスキー値と重複しない限り、インデックスキー値が繰り返される配列要素がドキュメントに含まれる場合があります。
この動作の詳細と例については、「複数の別個のドキュメント間での一意制約」を参照してください。
複合マルチキー インデックス
複合マルチキー インデックスでは、インデックス作成されたそれぞれのドキュメントに、値が配列であるインデックス付きフィールドを最大で 1 つ含めることができます。具体的な説明は以下の通りです。
インデックス仕様内の複数のフィールドが配列の場合、複合マルチキー インデックスを作成することはできません。
複合マルチキー インデックスがすでに存在する場合、この制限に違反するドキュメントを挿入することはできません。
例、moviesコレクションに複合マルチキーインデックス{ genres: 1, year: 1 } を作成できます。これは、各ドキュメントで、複合マルチキーインデックスでインデックス付けされた 1 つのフィールドのみが配列であるためです。genres フィールドと year フィールドの両方の配列値を含むドキュメントはありません。
ただし、複合マルチキー インデックスの作成後、genres フィールドと year フィールドの両方が配列であるドキュメントを挿入しようとすると、挿入は失敗します。
ソート
配列フィールドに対して マルチキーインデックス を使ってソートを行う場合、以下の両方の条件を満たさない限り、クエリプランには インメモリソート ステージが含まれます:
すべてのソートフィールドのインデックスの限界は
[MinKey, MaxKey]です。マルチキー インデックスの付いたフィールドの境界には、ソート パターンと同じパス プレフィックスはありません。
シャードキー
マルチキー インデックスをシャードキー インデックスとして指定することはできません。
ただし、シャードキー インデックスが複合インデックスのプレフィックスである場合、末尾のキー(シャードキーには含まれない)のいずれかが配列にインデックスを付けると、複合インデックスが複合マルチキー インデックスになる場合があります。
ハッシュされたインデックス
ハッシュされたインデックスをマルチキーにすることはできません。
カバード クエリ
次の条件が満たされている場合、マルチキー インデックスはクエリをカバーできます。
The query does not return the array field (meaning the array is not included in the query projection). This means that to cover a query, the multikey index must be compound.
クエリには
$elemMatchが含まれていません。このクエリは、対象となる他のすべてのクエリ要件を満たしています。
例、次の操作では、genres フィールドと title フィールドの moviesコレクションに複合マルチキーインデックスが作成されます。
db.movies.createIndex( { genres: 1, title: 1 } )
genres フィールドに配列値が含まれているため、上記のインデックスはマルチキーです。
インデックスは次のクエリをカバーします。
db.movies.find( { genres: 'Drama' }, { _id: 0, title: 1 } ).sort({ genres: 1 }).limit(5)
db.movies.find( { title: 'The Ace of Hearts', genres: 'Drama' }, { _id: 0, title: 1 } )
プロジェクションには genres 配列フィールドが含まれているため、インデックスは次のクエリをカバーしていません。
db.movies.find( { genres: 'Drama' }, { _id: 0, genres: 1 } ).limit(5)
配列フィールド全体に対するクエリ
クエリで配列全体の完全一致が指定されている場合、 MongoDB はマルチキーインデックスを使用して、その配列の最初の要素を含むドキュメントを検索します。ただし、インデックスのみを使用して配列全体を一致させることはできません。次に、 MongoDB は候補ドキュメントを取得し、それらをフィルタリングして、配列がクエリ配列と完全に一致するドキュメントのみを返します。
例、次の操作では、genresフィールドの moviesコレクションにマルチキーインデックスが作成されます。
db.movies.createIndex( { genres: 1 } )
次のクエリは、 genresフィールドが配列[ "Drama" ]であるドキュメントを検索します。
db.movies.find( { genres: 'Drama' }, { title: 1, genres: 1 } ).limit(5)
MongoDB ではマルチキー インデックスを使用して、 genres配列内の任意の位置に"Drama"を持つドキュメントを見つけることができます。次に、MongoDB でこれらのドキュメントが取得され、genres 配列がクエリ配列 [ "Drama" ] と等しいドキュメントがフィルタリングされます。
$expr
$expr 演算子はマルチキー インデックスをサポートしていません。
詳細
MongoDB でマルチキー インデックスの限界を組み合わせてパフォーマンスを向上させる方法については、「マルチキー インデックスの限界」を参照してください。
配列フィールドをクエリする方法については、以下を参照してください。