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

Unique Indexes

項目一覧

  • ユニークインデックスの作成
  • 動作

一意のインデックス により、インデックス フィールドに重複する値が保存されなくなります。 単一のフィールドに一意なインデックスを設定すると、特定のフィールドに値が最大 1 回表示されるようになります。 一意の複合インデックスを使用すると、インデックス キー値の任意の組み合わせが最大 1 回だけ表示されます。 MongoDB はデフォルトでは、コレクションの作成中に _idフィールドに一意のインデックスが作成されます。

でホストされる配置用MongoDB Atlas に、 一意のインデックスを UI に作成して管理 できます 。

ユニークインデックスを作成するには、unique オプションを true に設定した状態で、db.collection.createIndex() メソッドを使用します。

db.collection.createIndex( <key and index type specification>, { unique: true } )

たとえば、 membersコレクションのuser_idフィールドに一意のインデックスを作成するには、 mongoshで次の操作を使用します。

db.members.createIndex( { "user_id": 1 }, { unique: true } )

複合インデックスにも一意の制約を適用できます。 一意の複合インデックスでは、インデックス キー値の組み合わせに一意であることが強制されます。

たとえば、 membersコレクションのgroupNumberlastname 、およびfirstnameフィールドに一意のインデックスを作成するには、 mongoshで次の操作を使用します。

db.members.createIndex( { groupNumber: 1, lastname: 1, firstname: 1 }, { unique: true } )

作成されたインデックスでは、groupNumberlastnamefirstname の値の組み合わせは必然的に一意になります。

別の例として、次のドキュメントを含むコレクションを考えてみましょう。

{ _id: 1, a: [ { loc: "A", qty: 5 }, { qty: 10 } ] }

次のとおり、ユニークな複合マルチキー インデックスを a.loca.qty に作成します。

db.collection.createIndex( { "a.loc": 1, "a.qty": 1 }, { unique: true } )

ユニークインデックスを使用すると、a.loca.qty の値の 組み合わせが必然的に一意になるため、次のドキュメントをコレクションに挿入できます。

db.collection.insertMany( [
{ _id: 2, a: [ { loc: "A" }, { qty: 5 } ] },
{ _id: 3, a: [ { loc: "A", qty: 10 } ] }
] )

Tip

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

MongoDBは、コレクションにユニーク制約に違反するデータが既に含まれている場合、指定されたインデックス フィールドにユニークインデックスを作成できません。

ハッシュされたインデックスにユニーク制約を指定することはできません。

レプリカセットとシャーディングされたクラスターでローリング手順を使用してユニークインデックスを作成するには、その手順の実行中にコレクションへの書込みをすべて停止する必要があります。書込みを停止できない場合は、ローリング手順は使用せず、代わりに、次のいずれかを行ってコレクションにユニークインデックスを構築する必要があります。

  • レプリカセットのプライマリで db.collection.createIndex() を実行する

  • シャーディングされたクラスターのmongosdb.collection.createIndex()を実行

ユニーク制約は、コレクション内のドキュメントに個別に適用されます。具体的には、個別のドキュメントでインデックス キーの値が同じになることはありません。

この制約は個別のドキュメントに適用されるため、ユニークマルチキー インデックスの場合、ドキュメントに含まれる配列要素によって、そのドキュメントのインデックス キー値と別のドキュメントのインデックス キー値が重複していない限り、インデックス キー値の反復につながることがあります。この場合、反復されるインデックスエントリはインデックスに 1 度のみ挿入されます。

たとえば、次のドキュメントを含むコレクションで考えてみましょう。

{ _id: 1, a: [ { loc: "A", qty: 5 }, { qty: 10 } ] }
{ _id: 2, a: [ { loc: "A" }, { qty: 5 } ] }
{ _id: 3, a: [ { loc: "A", qty: 10 } ] }

次のとおり、ユニーク複合マルチキー インデックスを a.loca.qty に作成します。

db.collection.createIndex( { "a.loc": 1, "a.qty": 1 }, { unique: true } )

ユニークインデックスを使用すると、インデックスキー値が { "a.loc": "B", "a.qty": null } であるドキュメントが他にない場合は、次のドキュメントをコレクションに挿入できます。

db.collection.insertOne( { _id: 4, a: [ { loc: "B" }, { loc: "B" } ] } )

ドキュメントの単一フィールドのユニークインデックスのインデックス フィールドに null または欠損値がある場合、インデックスはそのドキュメントに null 値を保存します。単一フィールドのユニークインデックスはユニーク制約により、インデックスエントリに null 値を含むドキュメントを 1 つしか含めることができません。インデックスエントリに null 値があるドキュメントが複数ある場合、インデックス構築は重複キーエラーで失敗します。

x にユニークな単一フィールド インデックスがあるコレクションを例にしましょう。

db.collection.createIndex( { "x": 1 }, { unique: true } )

ユニークインデックスを使用しているため、x フィールドのないドキュメントがコレクションに既にない場合は、x フィールドがなくてもドキュメントを挿入できます。

db.collection.insertOne( { y: 1 } )

ただし、x フィールドのないドキュメントがコレクションに既に含まれている場合は、x フィールドがないとドキュメントを挿入できません。

db.collection.insertOne( { z: 1 } )

x フィールドの値に課されているユニーク制約に違反しているため、ドキュメントの挿入操作は失敗します。

WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error index: test.collection.$a.b_1 dup key: { : null }"
}
})

ドキュメントの複合ユニークインデックスの 1 つ以上のインデックス フィールドにnull または欠落値がある場合、インデックスは、ドキュメントのインデックスエントリ内の各 null または欠落フィールドに null 値を保存します。複合ユニークインデックスではユニーク制約により、複合ユニークインデックスでインデックスエントリ内のインデックス フィールドに null 値を含めることができるドキュメントは 1 つに限定されます。インデックス フィールドに null 値があるインデックスエントリが複数ある場合、インデックス構築は重複キーエラーで失敗します。MongoDB は、各インデックスエントリが一意である限り、複合ユニークインデックスに欠落フィールドがあるドキュメントを複数許容します。

たとえば、コレクション studentsnameagegrade の各フィールドに一ユニーク複合インデックスがあるとします。

db.students.createIndex(
{
"name": 1,
"age": -1,
"grade": 1
},
{ unique: true }
)

コレクションに既存の同一ドキュメントがない場合、ユニーク複合インデックスでは、grade フィールドがすべて欠落している次のドキュメントを挿入することができます。

db.students.insertMany(
{ "name": "Meredith", "age": 12 },
{ "name": "Olivia", "age": 11 },
{ "name": "Benjamin" }
)

ただし、インデックスキー(nameagegrade の値)がコレクション内の別のドキュメントと同じであるドキュメントは挿入できません。

db.students.insertOne( { name: "Meredith", age: 12 } )

nameagegrade の各フィールドの値に課されている一意という制約に違反しているため、ドキュメントの挿入操作は失敗します。

WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" :
"E11000 duplicate key error collection: test.students
index: name_1_age_-1_grade_1
dup key: { name: "Meredith", age: 12, grade: null }
}
} )

また、一意であっても既存のインデックスエントリとインデックスキーを共有するドキュメントは挿入できません。

db.students.insertOne( { name: "Olivia", "age": 11, "favorite color": "red"} )

nameagegrade の各フィールドの値に課されている一意という制約に違反しているため、ドキュメントの挿入操作は失敗します。

WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" :
"E11000 duplicate key error collection: test.students
index: name_1_age_-1_grade_1
dup key: { name: "Olivia", age: 11, grade: null }
}
} )

部分インデックスは、指定されたフィルター式を満たすコレクション内のドキュメントのみをインデックスします。partialFilterExpressionユニーク制約の両方を指定した場合、ユニーク制約はフィルター式を満たすドキュメントにのみ適用されます。

部分インデックスでユニーク制約を指定しても、ドキュメントがフィルタリング条件を満たさない場合は、当該ユニーク制約を満たさないドキュメントも挿入されます。例については、「ユニーク制約を持つ部分インデックス」を参照してください。

ハッシュされたインデックスにユニーク制約を指定することはできません。

範囲ベースのシャーディングされたコレクションでは、次のインデックスのみが一意である可能性があります。

  • シャードキーのインデックス

  • シャードキーがプレフィックス複合インデックス

  • デフォルトの _id インデックス。ただし_id フィールドがシャードキーまたはシャードキーのプレフィックスではない場合にのみ_id インデックスはシャードごとにユニーク制約を強制します。

    重要

    一意性と _id インデックス

    _id フィールドがシャードキーまたはシャードキーのプレフィックスではない場合、_id インデックスはシャードごとにユニーク制約を適用するだけで、シャード全体には適用されません

    たとえば、2 つのシャード A と B にまたがるシャーディングされたコレクション(シャードキー {x: 1})があるとします。_id キーはシャードキーの一部ではないため、コレクションには、シャード A に _id1 のドキュメントと、シャード B に _id1 のドキュメントがある可能性があります。

    _id フィールドがシャードキーでもシャードキーのプレフィックスでもない場合、MongoDB では、アプリケーションがシャード全体で _id 値の一意性を強制することを想定しています。

ユニークインデックスの制約とは、次のことを意味します。

  • シャーディングされたコレクションでは、コレクションに他のユニークインデックスがあると、そのコレクションをシャードできません。

  • すでにシャーディングされたコレクションでは、他のフィールドにユニークインデックスを作成することはできません。

シャードキーではないフィールドの一意性を維持するには、「任意のフィールドに対する一意の制約 」を参照してください。

MongoDB 5.0 以降、キー パターンが同じユニークスパースおよびユニーク非スパースインデックスを単一コレクションに混在させることができます。

次の例では、キー パターンが同じで sparse オプションが異なる複数のインデックスを作成します。

db.scoreHistory.createIndex( { score : 1 }, { name: "unique_index", unique: true } )
db.scoreHistory.createIndex( { score : 1 }, { name: "unique_sparse_index", unique: true, sparse: true } )

スパース オプションの有無にかかわらず、同じキー パターンで基本インデックスを作成することもできます。

db.scoreHistory.createIndex( { score : 1 }, { name: "sparse_index", sparse: true } )
db.scoreHistory.createIndex( { score : 1 }, { name: "basic_index" } )

MongoDB 5.0 以降、基本インデックスとユニークインデックスは同じキー パターンで共存できます。

重複するキー パターンが認められるため、インデックスを作成済みのフィールドにユニークインデックスを追加できます。

この例では、次のことが行われます。

キー パターン { score : 1 } を使用して基本インデックスを作成し、3 つのドキュメントを挿入します。

db.scoreHistory.createIndex( { score : 1 }, { name: "basic_index" } )
db.scoreHistory.insert( { score : 1 } )
db.scoreHistory.insert( { score : 2 } )
db.scoreHistory.insert( { score : 3 } )

同じキーパターン { score : 1 } を持つユニークインデックスを作成します。

db.scoreHistory.createIndex( { score : 1 }, { name: "unique_index", unique: true } )

score が重複するドキュメントの挿入を試みても、ユニークインデックスであるため失敗します。

db.scoreHistory.insert( { score : 3 } )

戻る

データの期限切れ