部分インデックスは、指定されたフィルター式を満たすコレクション内のドキュメントのみをインデックスします。 部分インデックスを使用すると、ストレージ必要量が少なくなり、インデックスの作成と維持の実行コストが減少します。
部分インデックスの作成
partial インデックスを作成するには、partialFilterExpression オプションを指定した db.collection.createIndex() メソッドを使用します。partialFilterExpression オプションは、以下を使用してフィルター条件を指定するドキュメントを受け入れます。
式(
field: valueまたは$eq演算子を使用するなど)$type式$and演算子$or演算子$in演算子$geoWithin演算子$geoIntersects演算子
例、次の操作では、genreフィールドが Drama であるドキュメントのみがインデックス化される複合インデックスが作成されます。
db.movies.createIndex( { title: 1 }, { partialFilterExpression: { genres: "Drama" } })MongoDB ではすべてのインデックス タイプで partialFilterExpression オプションを指定できます。時系列コレクションの TTL インデックスに partialFilterExpression を指定する場合、フィルタリング可能なコレクションは metaField のみです。
Tip
MongoDB Compass でインデックスを管理する方法については、「インデックスの管理」を参照してください。
動作
クエリ カバレッジ
MongoDB、インデックスの使用が不完全な結果セットにつながる場合、クエリまたはソート操作に部分インデックスは使用されません。
部分インデックスを使用するには、クエリ条件の一部としてフィルター式(またはフィルター式のサブセットが指定されるように変更されたフィルター式)をクエリに含める必要があります。
次のインデックスを例にしましょう。
db.users.createIndex( { name: 1 }, { partialFilterExpression: { password: { $exists: true } } })次のクエリではインデックスを使用できます。クエリ述語に含まれる条件 password: { $exists: true } がインデックスフィルター式password: { $exists: true } によってマッチングされるドキュメントと一致するためです。
db.users.find( { name: "Ned Stark", password: { $exists: true } } )ただし、次のクエリでは name フィールドに部分インデックスを使用できません。使用すると結果セットが不完全になるためです。具体的には、クエリ述語には条件 password: { $exists: false } が、インデックスにはフィルター password: { $exists: true } が含まれます。つまり、クエリ { name: "Ned Stark", password: { $exists: false } } は、部分インデックスに含まれていないドキュメント(パスワードのないユーザー)と一致します。
db.users.find( { name: "Ned Stark", password: { $exists: false } } )同様に、次のクエリでも部分インデックスを使用できません。クエリ述語にフィルター式が含まれておらず、インデックスを使用すると不完全な結果セットが返されるためです。
db.users.find( { name: "Ned Stark" } )比較演算子
$gt などの比較演算子を使用するインデックスの場合、クエリ条件が等しいか、より狭い値の範囲を指定していれば、そのクエリ条件はフィルター式を満たします。
例、フィルター式 { year: { $gt: 2000 } } を持つインデックスがあるとします。
db.movies.createIndex( { year: 1 }, { name: "year_gt_2000_partial", partialFilterExpression: { year: { $gt: 2000 } } })次のクエリでは、条件 year: 2005 がフィルター式によってマッチングされるドキュメントのサブセットと一致するため、インデックスを使用できます。
db.movies.find( { year: 2005 } ).explain("executionStats")同様に、次のクエリでは、条件 year: { $gt: 2010 } がフィルター式よりも狭い範囲のドキュメントと一致するため、インデックスを使用できます。
db.movies.find( { year: { $gt: 2010 } } ).explain("executionStats")ただし、次のクエリは、条件 year: { $gt: 1990 } が部分インデックスに含まれていないドキュメントと一致するため、インデックスを使用できません。
db.movies.find( { year: { $gt: 1990 } } ).explain("executionStats")注意
サブセットマッチングは、partialFilterExpressionでサポートされているすべての演算子で同じように動作するわけではありません。ここに示されていないクエリパスワードなしで部分インデックスを使用する前に、explain()を使用して、MongoDBが期待どおりのインデックスを選択することを確認してください。
スパースインデックスとの比較
インデックスを作成するdocumentをより正確に制御するには、スパースインデックスではなく部分インデックスを使用します。
スパース インデックスでは、インデックス付きフィールド(またはスパース複合インデックスの場合は複数のフィールド)の存在のみを基準にドキュメントを含めるか除外します。
部分インデックスでは、フィルター式に基づいてドキュメントを含めるか除外します。式にはインデックスキー以外のフィールドを含めることができ、フィールドが存在する以外の条件を指定できます。
例、部分インデックスでは スパースインデックスと同じ動作を実装できます。 上記の部分インデックスでは、nameフィールドのスパースインデックスと同じクエリをサポートします。
db.users.createIndex( { name: 1 }, { partialFilterExpression: { name: { $exists: true } } })ただし、部分インデックスでは、インデックスキー以外のフィールドをフィルタリングすることもできます。例、nameフィールドの部分インデックスでは、 emailフィールドの存在を確認できます。
db.users.createIndex( { name: 1 }, { partialFilterExpression: { email: { $exists: true } } })クエリオプティマイザがこのタイプの部分インデックスを選択するには、name フィールドの条件に加え email フィールドの null 以外の一致条件がクエリ述語に含まれている必要があります。
たとえば、次のクエリには、name フィールドの条件と email フィールドの null 以外の一致の両方が含まれているため、インデックスを使用できます。
db.users.find( { name: "Ned Stark", email: { $regex: /gameofthron\.es$/ } } )一方、次のクエリでは、フィルター式{ email: { $exists: true } } で許可されていない null マッチが email フィールドに含まれているため、インデックスを使用できません。
db.users.find( { name: "Ned Stark", email: { $exists: false } } )部分的な TTL インデックス
部分インデックスは TTL インデックスにすることもできます。部分 TTL インデックスを使用すると、指定されたフィルター式に一致するドキュメントのみが期限切れになります。詳細については、「フィルター条件でドキュメントを期限切れにする」を参照してください。
制限事項
partialFilterExpressionオプションとsparseオプションを両方指定することはできません。_idインデックスは部分インデックスにできません。シャードキー インデックスは部分インデックスにできません。
クライアント側フィールドレベル暗号化またはQueryable Encryptionを使用している場合、
partialFilterExpressionは暗号化されたフィールドを参照できません。
等価インデックス
MongoDB 7.3以降では、 同等のインデックス は作成できません。これは、同じインデックス キーと照合を使用する同じ部分式を持つ部分インデックスです。
既存の同等インデックスを持つ MongoDB 7.3のデータベースの場合、インデックスは保持されますが、クエリで使用されるのは最初の同等インデックスのみです。 これは、 7.3より前の MongoDB バージョンと同じです。
例、部分フィルター式内のテキスト大文字と小文字が異なる 2 つのインデックスは作成できません。
例
このページの例では、sample_mflix データセット のデータを使用しています。自己管理型 MongoDB 配置にこのデータセットをロードする方法の詳細については、「サンプル データセットのロード」を参照してください。サンプル データベースに何らかの変更を加えた場合は、今ページの例を実行するには、データベースを削除して再作成する必要がある可能性があります。
コレクションでの部分インデックスの作成
次の例では、title フィールドと genres フィールドに部分インデックスを追加します。この操作では、ratingフィールドが PG であるドキュメントのみがインデックス化されます。
db.movies.createIndex( { title: 1, genres: 1 }, { partialFilterExpression: { rated: "PG" } })moviesコレクションに対する次のクエリでは、部分インデックスを使用して、「3 つのファイル」というタイトルのすべての映画のライターが返されます。
db.movies.find( { title: "The Three Musketeers", genres: ["Action", "Adventure", "Comedy"], rated: "PG" }, { writers: 1 } )一方、次のクエリでは、クエリ述語に rating フィルターが含まれていないため、部分インデックスを使用できません。
db.movies.find( { genres: "Drama" }, { title: 1 } ).limit(5)ユニーク制約を持つ部分インデックス
部分インデックスでは、コレクション内のドキュメントのうち、指定フィルター式を満たすコものにのみインデックスが作成されます。partialFilterExpression とユニーク制約の両方を指定した場合、ユニーク制約はフィルター式を満たすドキュメントにのみ適用されます。部分インデックスでユニーク制約を指定しても、ドキュメントがフィルタリング条件を満たさない場合は、当該ユニーク制約を満たさないドキュメントも挿入されます。
コレクションに対する次の操作では、users emailフィールドと部分的なフィルター式password: { $exists: true } に一意の制約を指定するインデックスが作成されます。
db.users.createIndex( { email: 1 }, { unique: true, partialFilterExpression: { password: { $exists: true } } })インデックスは、コレクション内にすでに存在するメールアドレスと既存の passwordフィールド の両方を持つdocumentは挿入できなくなります。
ただし、ドキュメントに password フィールドが含まれていない場合は、重複する email アドレスを持つドキュメントを挿入できます。一意の制約は、インデックスに含まれるドキュメントにのみ適用されます。次の例では、同じメールアドレスを持つ2つのドキュメントを挿入します。
db.users.insertMany( [ // This document has a password field, so the index includes it and // the unique constraint applies to its email address { name: "Jon Snow", email: "jon@example.com", password: "example123" },
// This document does not have a password field, so the index does not // include it. You can insert it even though it has the same email // address as the first document { name: "Jon Snow", email: "jon@example.com" }] )