MongoDB で unique 制約を適用する方法

今回は「MongoDB で unique 制約を適用する方法」について見てみよう。

unique 制約の適用

MongoDB で unique 制約を適用するには、インデックスを作成するときに createIndex() のオプションとして uniquetrue を指定すればよい。

以下では、「単一キーインデックス」の場合と「複合キーインデックス」の場合について、サンプルコードを見ていく。

単一キーインデックス

単一キーインデックスであれば、単純に次のようなコードを mongo シェルで実行すると作成できる。

> db.members.createIndex({ userId: 1 }, { unique: true })

複合キーインデックス

複合キーインデックスの場合も、単一キーインデックスとコードは変わらない。

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

複合キーインデックスの場合、複合キーの組み合わせとして一意であればよいため、以下は問題なく設定できる。

> db.members.insert({ firstname: "kc", lastname: "Kim" })
> db.members.insert({ firstname: "et", lastname: "Kim" })
> db.members.insert({ firstname: "kc" })

unique 制約の設定制限

RDB の場合と似ているが、すでに重複データが登録されているコレクションに対して unique 制約を設定することはできない。すでに重複している状態では当然と言えば当然である。

また、ハッシュインデックスに対して unique 制約を設定することは推奨されない。(Hashed Indexes の Considerations)

unique 制約キーに値が設定されていない場合の動作

上で「複合キーインデックス」に unique 制約を設定したデータ登録例のように、値がないフィールドが存在する場合、内部的には null が指定されたものとして処理される。

たとえば、次のようにフィールド x に対する unique 制約があるコレクションがあるとする。

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

フィールド x を指定しないデータが登録されたと仮定する。

> db.collection.insert({ y: 1 })
WriteResult({ "nInserted" : 1 })

最初は x: null として指定されるため、正常に登録できる。続けて、フィールド x が存在しない別のデータを挿入するとどうなるだろうか。

> db.collection.insert({ z: 1 })
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 11000,
        "errmsg" : "E11000 duplicate key error collection: test.collection index: x_1 dup key: { : null }"
    }
})

上記のようにエラーが発生し、挿入できないことがわかる。また、エラーメッセージからも、指定がない場合は null が指定されることがわかる。

参考文書