Docs Menu
Docs Home
/
MongoDBマニュアル
/ /

部分インデックス

項目一覧

  • 部分インデックスの作成
  • 動作
  • 制限事項

部分インデックスでは、コレクション内のドキュメントのうち、指定フィルター式を満たすコものにのみインデックスが作成されます。コレクションのドキュメントのサブセットがインデックス化されるため、ストレージ必要量が少なくなり、インデックスの作成と維持の実行コストが減少します。

partial インデックスを作成するには、partialFilterExpression オプションを指定したdb.collection.createIndex() メソッドを使用します。partialFilterExpression オプションは、次のことを使用してフィルター条件を指定するドキュメントを受け入れます。

  • 等式(field: value または $eq 演算子を使用するなど)

  • $exists: true

  • $gt, $gte, $lt, $lte expressions,

  • $type

  • $and 演算子

  • $or 演算子

  • $in 演算子

たとえば、次の操作で作成される複合インデックスでは、rating フィールドが 5 を超えるドキュメントのみがインデックス化されます。

db.restaurants.createIndex(
{ cuisine: 1, name: 1 },
{ partialFilterExpression: { rating: { $gt: 5 } } }
)

MongoDB ではすべてのインデックス タイプpartialFilterExpression オプションを指定できます。時系列コレクションの TTL インデックスに partialFilterExpression を指定する場合、フィルタリング可能なコレクションは metaField のみです。

Tip

以下も参照してください。

MongoDB Compass でインデックスを管理する方法については、「インデックスの管理」を参照してください。

MongoDB では、インデックスの使用が不完全な結果セットにつながる場合、クエリまたはソート操作に部分インデックスは使用されません。

部分インデックスを使用するには、クエリ条件の一部としてフィルター式(またはフィルター式のサブセットが指定されるように変更されたフィルター式)をクエリに含める必要があります。

次のインデックスを例にしましょう。

db.restaurants.createIndex(
{ cuisine: 1 },
{ partialFilterExpression: { rating: { $gt: 5 } } }
)

次のクエリではインデックスを使用できます。クエリ述語に含まれる条件 rating: { $gte: 8 }がインデックス フィルター式 rating: { $gt: 5 } によってマッチングされるドキュメントのサブセットと一致するためです。

db.restaurants.find( { cuisine: "Italian", rating: { $gte: 8 } } )

ただし、次のクエリでは cuisine フィールドに部分インデックスックスを使用できません。使用すると結果セットが不完全になるためです。具体的には、クエリ述語には条件 rating: { $lt: 8 }が、インデックスにはフィルター rating: { $gt: 5 } が含まれます。そのため、クエリ { cuisine: "Italian", rating: { $lt: 8 } } に一致するドキュメントの数は、インデックス作成時よりも多くなります(評価が 1 のイタリアン レストランなど)。

db.restaurants.find( { cuisine: "Italian", rating: { $lt: 8 } } )

同様に、次のクエリでも部分インデックスを使用できません。クエリ述語にフィルター式が含まれておらず、インデックスを使用すると不完全な結果セットが返されるためです。

db.restaurants.find( { cuisine: "Italian" } )

部分インデックスは、スパースインデックスよりも優先され、次の利点を有します。

  • どのドキュメントのインデックスを作成するかをより細かく制御できる。

  • スパースインデックスの上位機能を提供する。

スパースインデックスでは、インデックスが作成されたフィールドがあること(複合インデックスの場合は、インデックスが作成されたフィールドが複数あること)のみを基準にインデックスを作成するドキュメントが選択されます。

部分インデックスでは、指定フィルターを基準にインデックスエントリが決定されます。フィルターにはインデックス キー以外のフィールドを含めることができ、インデックスの有無以外の条件も指定可能です。たとえば、部分インデックスではスパースインデックスと同じ動作を実装できます。

db.contacts.createIndex(
{ name: 1 },
{ partialFilterExpression: { name: { $exists: true } } }
)

上記の部分インデックスでは、name フィールドでスパースインデックスと同じクエリをサポートします。

ただし、部分インデックスでは、インデックス キー以外のフィールドにフィルター式を指定することもできます。たとえば、次の操作で作成される部分インデックスには、name フィールドにインデックスがあるだけでなく、email フィールドにフィルター式もあります。

db.contacts.createIndex(
{ name: 1 },
{ partialFilterExpression: { email: { $exists: true } } }
)

クエリオプティマイザがこのタイプの部分インデックスを選択するには、name フィールドの条件に加え email フィールドの null 以外の一致条件がクエリ述語に含まれている必要があります。

たとえば、次のクエリには、name フィールドの条件と email フィールドの null 以外の一致の両方が含まれているため、インデックスを使用できます。

db.contacts.find( { name: "xyz", email: { $regex: /\.org$/ } } )

一方、次のクエリでは、フィルター式{ email: { $exists: true } } で許可されていない null マッチが email フィールドに含まれているため、インデックスを使用できません。

db.contacts.find( { name: "xyz", email: { $exists: false } } )

部分インデックスは TTL インデックスにすることもできます。部分 TTL インデックスを使用すると、指定されたフィルター式に一致するドキュメントのみが期限切れになります。詳細については、「フィルター条件でドキュメントを期限切れにする」を参照してください。

  • partialFilterExpression オプションと sparse オプションを両方指定することはできません。

  • _id インデックスは部分インデックスにできません。

  • シャードキー インデックスは部分インデックスにできません。

  • クライアント側フィールドレベル暗号化またはQueryable Encryptionを使用している場合、 partialFilterExpressionは暗号化されたフィールドを参照できません。

MongoDB 7.3以降では、 同等のインデックス は作成できません。これは、同じインデックス キーと照合を使用する同じ部分式を持つ部分インデックスです。

既存の同等インデックスを持つ MongoDB 7.3のデータベースの場合、インデックスは保持されますが、クエリで使用されるのは最初の同等インデックスのみです。 これは、 7.3より前の MongoDB バージョンと同じです。

例については、「 等価インデックスの例 」を参照してください。

次のようなドキュメントが含まれているコレクション restaurants を例に挙げます。

{
"_id" : ObjectId("5641f6a7522545bc535b5dc9"),
"address" : {
"building" : "1007",
"coord" : [
-73.856077,
40.848447
],
"street" : "Morris Park Ave",
"zipcode" : "10462"
},
"borough" : "Bronx",
"cuisine" : "Bakery",
"rating" : { "date" : ISODate("2014-03-03T00:00:00Z"),
"grade" : "A",
"score" : 2
},
"name" : "Morris Park Bake Shop",
"restaurant_id" : "30075445"
}

boroughcuisine の各フィールドに部分インデックスを追加すると、rating.grade フィールドが A のドキュメントのみでインデックスを作成できます。

db.restaurants.createIndex(
{ borough: 1, cuisine: 1 },
{ partialFilterExpression: { 'rating.grade': { $eq: "A" } } }
)

この場合、restaurants コレクションへの次のクエリでは部分インデックスを使用して、rating.gradeA に等しいブロンクスのレストランが返されます。

db.restaurants.find( { borough: "Bronx", 'rating.grade': "A" } )

一方、次のクエリでは、クエリ述語にrating.gradeフィールドが含まれていないため、部分インデックスを使用できません。

db.restaurants.find( { borough: "Bronx", cuisine: "Bakery" } )

部分インデックスでは、コレクション内のドキュメントのうち、指定フィルター式を満たすコものにのみインデックスが作成されます。partialFilterExpressionユニーク制約の両方を指定した場合、ユニーク制約はフィルター式を満たすドキュメントにのみ適用されます。部分インデックスでユニーク制約を指定しても、ドキュメントがフィルタリング条件を満たさない場合は、当該ユニーク制約を満たさないドキュメントも挿入されます。

たとえば、コレクション users に次のドキュメントが含まれているとします。

{ "_id" : ObjectId("56424f1efa0358a27fa1f99a"), "username" : "david", "age" : 29 }
{ "_id" : ObjectId("56424f37fa0358a27fa1f99b"), "username" : "amanda", "age" : 35 }
{ "_id" : ObjectId("56424fe2fa0358a27fa1f99c"), "username" : "rajiv", "age" : 57 }

次の操作では、username フィールドにユニーク制約と部分的なフィルター式 age: { $gte: 21 } を指定するインデックスが作成されます。

db.users.createIndex(
{ username: 1 },
{ unique: true, partialFilterExpression: { age: { $gte: 21 } } }
)

このインデックスにより次のドキュメントは挿入できなくなります。指定されたユーザー名を持ち、age フィールドが 21 を超えるドキュメントがすでにあるためです。

db.users.insertMany( [
{ username: "david", age: 27 },
{ username: "amanda", age: 25 },
{ username: "rajiv", age: 32 }
] )

ただし、ユニーク制約が適用されるのは、age が 21 以上のドキュメントのみであるため、ユーザー名が重複している次のドキュメントは許可されます。

db.users.insertMany( [
{ username: "david", age: 20 },
{ username: "amanda" },
{ username: "rajiv", age: null }
] )

MongoDB 7.3以降では、 同等のインデックス は作成できません。これは、同じインデックス キーと照合を使用する同じ部分式を持つ部分インデックスです。

既存の同等インデックスを持つ MongoDB 7.3のデータベースの場合、インデックスは保持されますが、クエリで使用されるのは最初の同等インデックスのみです。 これは、 7.3より前の MongoDB バージョンと同じです。

前の MongoDB バージョンでは、2 つの同等のインデックスを作成できます。 次の例では、 pizzasコレクションと、 index0index1という名前の 2 つの同等のインデックスを作成します。

// Create the pizzas collection
db.pizzas.insertMany( [
{ _id: 0, type: "pepperoni", size: "small", price: 4 },
{ _id: 1, type: "cheese", size: "medium", price: 7 },
{ _id: 2, type: "vegan", size: "large", price: 8 }
] )
// Create two equivalent indexes with medium pizza sizes
db.pizzas.createIndex(
{ type: 1 },
{ name: "index0",
partialFilterExpression: { size: "medium" },
collation: { locale: "en_US", strength: 1 }
}
)
db.pizzas.createIndex(
{ type: 1 },
{ name: "index1",
partialFilterExpression: { size: "MEDIUM" },
collation: { locale: "en_US", strength: 1 }
}
)

インデックスは同等です。指定するのは 2 つのインデックスが同じピザ サイズを指定し、部分フィルター式のテキストケースのみが異なるためです。 クエリでは 1 つのインデックスのみが使用されます。これは最初に作成されたインデックスで、前の例ではindex0です。

MongoDB 7.3以降では、2 番目のインデックス( index1 )を作成できず、次のエラーが返されます。

MongoServerError: Index already exists with a different name: index0

7.3より前のバージョンの MongoDB ではインデックスを作成できますが、これらのクエリで使用されるのは最初のインデックス( index0 )のみです。

db.pizzas.find( { type: "cheese", size: "medium" } ).collation(
{ locale: "en_US", strength: 1 }
)
db.pizzas.find( { type: "cheese", size: "MEDIUM" } ).collation(
{ locale: "en_US", strength: 1 }
)
db.pizzas.find( { type: "cheese", size: "Medium" } ).collation(
{ locale: "en_US", strength: 1 }
)

戻る

hidden