スパース インデックスには、インデックス フィールドに null 値が含まれていても、インデックスフィールドを持つドキュメントのエントリのみが含まれます。インデックスは、インデックス付きフィールドが欠落しているドキュメントをスキップします。コレクションのすべてのドキュメントが含まれているわけではないため、インデックスは "スパース" です。一方、非スパース インデックスにはコレクション内のすべてのドキュメントが含まれ、インデックス フィールドを含まないドキュメントには null 値がストアされます。
重要
部分インデックスはスパースインデックスとして機能できますが、フィールドが存在するかどうかを超える条件のフィルター式もサポートします。正確なフィルタリングが必要な場合は、より詳細な制御を行うために 部分インデックスを使用してください。
スパース インデックスの作成
スパース インデックスを作成するには、sparse オプションを true に設定した db.collection.createIndex() メソッドを使用します。
たとえば、 mongoshの次の操作では、movies コレクションの plot フィールドにsparse indexが作成されます。
db.movies.createIndex( { "plot": 1 }, { sparse: true } )
インデックスは、plot フィールドを含まないドキュメントをインデックスしません。
注意
MongoDB のスパース インデックスと、他のデータベースのブロックレベル インデックスを混同しないでください。特定のフィルターを備えた密なインデックスと考えてください。
動作
スパース インデックスと不完全な結果
スパース インデックスによって、クエリやソート操作の結果セットが不完全になる場合、hint() で明示的にインデックスを指定しない限り、MongoDB はそのインデックスを使用しません。
たとえば、クエリ { plot: { $exists: false } } では、明示的なヒントがない限り plot フィールドにスパース インデックスを使用しません。動作の詳細を示す例については、「コレクションのスパース インデックスが完全な結果を返さない」を参照してください。
コレクション内のすべてのドキュメントの count() を実行するときに、スパース インデックスを指定する hint() を含めると(つまり、クエリ述語が空の場合)、スパース インデックスの結果が不正確なカウントになった場合でも、スパース インデックスが使用されます。
例、moviesコレクションの ratedフィールドにスパースインデックスを作成します。
db.movies.createIndex( { rated: 1 }, { sparse: true } )
moviesコレクション内のドキュメントの数をカウントし、その スパースインデックスを指定するヒントを含めると、操作はratedフィールドを含むドキュメントのみを返します。
db.movies.countDocuments( {}, { hint: { rated: 1 } } )
moviesコレクション内のドキュメント数の正確なカウントを取得するには、コレクション内のすべてのドキュメントのカウントを実行するときに、スパースインデックスを使用してhint() を実行しないでください。
db.movies.countDocuments()
デフォルトでスパースなインデックス
次のインデックスの種類は、常にスパースです。
スパース複合インデックス
複合インデックスには、さまざまなタイプのスパースインデックスを含めることができます。インデックスのタイプの組み合わせによって、複合インデックスがドキュメントと一致する方法が決まります。
下表には、さまざまなタイプのスパースインデックスを含む複合インデックスの動作がまとめられています。
複合インデックスの構成要素 | 複合インデックスの動作 |
|---|---|
Ascending indexes Descending indexes | 1 つ以上のキーの値を含むドキュメントのみ、インデックスが作成されます。 |
| |
|
スパースでユニークなプロパティ
インデックスがスパースかつ一意の場合、フィールドの値が重複するドキュメントがコレクションに含まれることはありませんが、キーが省略された複数のドキュメントは許可されます。
例
コレクションでのスパース インデックスの作成
次の例では、フィールドpassword にスパースインデックスを作成しています。
db.users.createIndex( { password: 1 } , { sparse: true } )
次に、usersコレクションに対する次のクエリは、スパースインデックスを使用して、passwordフィールドを持つドキュメントを返します。
db.users.find( { password: { $exists: true } } ).sort({ password: 1 }).limit(5)
ユーザーに passwordフィールドが含まれていない場合、クエリはそのユーザーを返しません。
コレクションのスパース インデックスが完全な結果を返せない
一部のドキュメントには plotフィールドがない場合がある moviesコレクションについて考えてみましょう。
次の例では、フィールドplot にスパースインデックスを作成しています。
db.movies.createIndex( { "plot": 1 }, { sparse: true } )
movies コレクションのすべてのドキュメントを plot フィールドでソートして返すには、次のクエリを考慮します:
db.movies.find().sort( { plot: -1 } )
インデックス付きフィールドで並べ替えても、 コレクション内の一部のドキュメントには フィールドがない場合、 MongoDB は完全な結果を返すことを目的としてクエリを満たすために、スパースインデックスを選択することはmoviesplot ありません 。
スパース インデックスを使用するには、hint() を使用してインデックスを明示的に指定します。
db.movies.find().sort( { plot: -1 } ).hint( { plot: 1 } ).limit(5)
このクエリは、plotフィールドを含む moviesコレクション内のドキュメントのみを返します。
ユニーク制約を持つスパース インデックス
次の操作では、 の フィールドに 一意の制約 とスパースフィルターを持つインデックスが作成されます。passwordusers
db.users.createIndex( { password: 1 } , { sparse: true, unique: true } )
このインデックスにより、password フィールドにユニークな値を持つドキュメント、あるいは password フィールドが含まれていないドキュメントの挿入が許可されます。そのため、users コレクション内の既存のドキュメントを前提として、インデックスでは以下の挿入操作が可能です。
db.users.insertMany( [ { "name": "Jon Snow", "email": "jon@gameofthron.es", "password": "$2b$12$newHashedPassword1234567890ABC" }, { "name": "Sansa Stark", "email": "sansa@gameofthron.es", "password": "$2b$12$anotherNewPassword1234567890DEF" }, { "name": "Bran Stark", "email": "bran@gameofthron.es" } ] )
ただし、インデックスではコレクションにすでに存在するメールアドレスを含むドキュメントの追加は 許可されません 。
ユニークスパース/非スパースインデックス
MongoDB5.0 以降、 キー パターン が同じ 一意のスパース および 一意の非スパース インデックスを単一コレクションに混在させることができます。
ユニークおよびスパースインデックスの作成
次の例では、キー パターンが同じで sparse オプションが異なる複数のインデックスを作成します。
db.users.createIndex( { password : 1 }, { name: "unique_index", unique: true } )
db.users.createIndex( { password : 1 }, { name: "unique_sparse_index", unique: true, sparse: true } )
基本インデックスとスパースインデックスの作成
スパース オプションの有無にかかわらず、同じキー パターンで基本インデックスを作成することもできます。
db.users.createIndex( { password : 1 }, { name: "sparse_index", sparse: true } )
db.users.createIndex( { password : 1 }, { name: "basic_index" } )