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
コレクションのgroupNumber
、 lastname
、およびfirstname
フィールドに一意のインデックスを作成するには、 mongosh
で次の操作を使用します。
db.members.createIndex( { groupNumber: 1, lastname: 1, firstname: 1 }, { unique: true } )
作成されたインデックスでは、groupNumber
、lastname
、firstname
の値の組み合わせは必然的に一意になります。
別の例として、次のドキュメントを含むコレクションを考えてみましょう。
{ _id: 1, a: [ { loc: "A", qty: 5 }, { qty: 10 } ] }
次のとおり、ユニークな複合マルチキー インデックスを a.loc
と a.qty
に作成します。
db.collection.createIndex( { "a.loc": 1, "a.qty": 1 }, { unique: true } )
ユニークインデックスを使用すると、a.loc
と a.qty
の値の 組み合わせが必然的に一意になるため、次のドキュメントをコレクションに挿入できます。
db.collection.insertMany( [ { _id: 2, a: [ { loc: "A" }, { qty: 5 } ] }, { _id: 3, a: [ { loc: "A", qty: 10 } ] } ] )
動作
制限事項
MongoDBは、コレクションにユニーク制約に違反するデータが既に含まれている場合、指定されたインデックス フィールドにユニークインデックスを作成できません。
ハッシュされたインデックスにユニーク制約を指定することはできません。
レプリカセットとシャーディングされたクラスターでのユニークインデックスの構築
レプリカセットとシャーディングされたクラスターでローリング手順を使用してユニークインデックスを作成するには、その手順の実行中にコレクションへの書込みをすべて停止する必要があります。書込みを停止できない場合は、ローリング手順は使用せず、代わりに、次のいずれかを行ってコレクションにユニークインデックスを構築する必要があります。
レプリカセットのプライマリで
db.collection.createIndex()
を実行するシャーディングされたクラスターの
mongos
でdb.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.loc
と a.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 は、各インデックスエントリが一意である限り、複合ユニークインデックスに欠落フィールドがあるドキュメントを複数許容します。
たとえば、コレクション students
の name
、age
、grade
の各フィールドに一ユニーク複合インデックスがあるとします。
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" } )
ただし、インデックスキー(name
、age
、grade
の値)がコレクション内の別のドキュメントと同じであるドキュメントは挿入できません。
db.students.insertOne( { name: "Meredith", age: 12 } )
name
、age
、grade
の各フィールドの値に課されている一意という制約に違反しているため、ドキュメントの挿入操作は失敗します。
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"} )
name
、age
、grade
の各フィールドの値に課されている一意という制約に違反しているため、ドキュメントの挿入操作は失敗します。
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 に_id
値1
のドキュメントと、シャード B に_id
値1
のドキュメントがある可能性があります。_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 } )