ユニークインデックスにより、インデックス フィールドに重複する値が保存されなくなり、特定のフィールドに値が最大 1 回表示されるようになります。一意の複合インデックスを使用すると、インデックスキー値の任意の組み合わせが最大 1 回表示されるようになります。デフォルトでは、 MongoDB はコレクションの作成 中にユニークインデックスを_idフィールドに作成します。
ユニークインデックスの作成
ユニークインデックスを作成するには、unique オプションを true に設定した状態で、db.collection.createIndex() メソッドを使用します。
db.collection.createIndex( <key and index type specification>, { unique: true } )単一フィールドのユニークインデックス
たとえば、 usersコレクションのemailフィールドに一意のインデックスを作成するには、 mongoshで次の操作を使用します。
db.users.createIndex( { "email": 1 }, { unique: true } )ユニーク複合インデックス
複合インデックスのインデックスキー値の組み合わせに一意の制約を強制することもできます。
たとえば、 usersコレクションのname 、 email 、およびpasswordフィールドに一意のインデックスを作成するには、 mongoshで次の操作を使用します。
db.users.createIndex( { name: 1, email: 1, password: 1 }, { unique: true } )次のとおり、ユニークな複合マルチキー インデックスを email と name に作成します。
db.users.createIndex( { "email": 1, "name": 1 }, { unique: true } )ユニークインデックスを使用すると、email と name の値の 組み合わせが必然的に一意になるため、次のドキュメントをコレクションに挿入できます。
db.users.insertMany( [ { name: "Catelyn Stark", email: [ "catelyn@gameofthron.es", "sean_bean@gameofthron.es" ], password: "$2b$12$hash2" }, { name: "Arya Stark", email: [ "catelyn@gameofthron.es" ], password: "$2b$12$hash3" }] )両方のドキュメントで "catelyn@gameofthron.es" が email 配列に含まれていても、nameフィールドと各メール値の組み合わせは一意であるため、操作は成功します。
動作
制限事項
MongoDBは、コレクションにユニーク制約に違反するデータが既に含まれている場合、指定されたインデックス フィールドにユニークインデックスを作成できません。
既存の非ユニークインデックスをユニークインデックスに変換する方法については、「既存のインデックスをユニークインデックスに変換する」を参照してください。
ハッシュされたインデックスにユニーク制約を指定することはできません。
レプリカセットとシャーディングされたクラスターでのユニークインデックスの構築
レプリカセットとシャーディングされたクラスターでローリング手順を使用してユニークインデックスを作成するには、その手順の実行中にコレクションへの書込みをすべて停止する必要があります。書込みを停止できない場合は、ローリング手順は使用せず、代わりに、次のいずれかを行ってコレクションにユニークインデックスを構築する必要があります。
レプリカセットのプライマリで
db.collection.createIndex()を実行するシャーディングされたクラスターの
mongosでdb.collection.createIndex()を実行
個別ドキュメント間でのユニーク制約
ユニークインデックスすると、コレクション内のさまざまなdocumentでインデックス キーの値が同じになることはありません。
この制約は個別のドキュメントに適用されるため、ユニークマルチキー インデックスの場合、ドキュメントに含まれる配列要素によって、そのドキュメントのインデックス キー値と別のドキュメントのインデックス キー値が重複していない限り、インデックス キー値の反復につながることがあります。この場合、反復されるインデックスエントリはインデックスに 1 度のみ挿入されます。
例、email と name に一意の複合マルチキーインデックスを作成します。
db.users.createIndex( { "email": 1, "name": 1 }, { unique: true } )ユニークインデックスを使用すると、インデックスキー値が { "email": "arya@winterfell.com", "name": null } であるドキュメントが他にない場合は、次のドキュメントをコレクションに挿入できます。
db.users.insertOne( { _id: ObjectId("59b99db4cfa9a34dcd7885b9"), email: [ "arya@winterfell.com", "arya@gameofthron.es" ] } )ユニークな単一フィールド インデックス内でのドキュメント フィールドの欠落
ドキュメントの単一フィールドのユニークインデックスのインデックス フィールドに null または欠損値がある場合、インデックスはそのドキュメントに null 値を保存します。単一フィールドのユニークインデックスはユニーク制約により、インデックスエントリに null 値を含むドキュメントを 1 つしか含めることができません。インデックスエントリに null 値があるドキュメントが複数ある場合、インデックス構築は重複キーエラーで失敗します。
email にユニークな単一フィールド インデックスがあるコレクションを例にしましょう。
db.users.createIndex( { "email": 1 }, { unique: true } )ユニークインデックスを使用しているため、emailフィールドのないdocumentがコレクションに既にない場合は、emailフィールドがなくてもdocumentを挿入できます。
db.users.insertOne( { name: "Arya Stark" } )ただし、 emailフィールドのないdocumentがコレクションにすでに含まれている場合は、emailフィールドがないと 2 番目のdocumentを挿入できません。emailフィールドなしで別のdocumentを挿入しようとする 2 番目の操作は、emailフィールドの一意の制約に違反しているため、失敗します。
ユニーク部分インデックス
partialFilterExpression とユニーク制約の両方を使用する場合、ユニーク制約はフィルター式 を満たす document にのみ適用されます。例については、一意の制約を持つ部分インデックスを参照してください。
シャーディングされたクラスターとユニークインデックス
シャードクラスターがシャード全体にユニーク制約を強制するのは、ユニークインデックスがシャードキー上にあるか、またはシャードキーをプレフィックス として含む場合のみです。ハッシュされたインデックスにユニーク制約を指定することはできません。
シャーディングされたコレクションのユニークインデックスに適用される制限と、シャードキーではないフィールドで一意性を維持する方法については、「シャーディングされたクラスターで一意性を維持する」を参照してください。
ユニークスパース/非スパースインデックス
MongoDB 5.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" } )キー パターンが重複する基本インデックスとユニークインデックス
基本インデックスとユニークインデックスは、同じキー パターンを持つことができます。
例では、同じキー パターンを使用する次の両方のインデックスを作成できます。
db.users.createIndex( { email : 1 }, { name: "basic_index" } )db.users.createIndex( { email : 1 }, { name: "unique_index", unique: true } )