Unique Indexes
고유 인덱스는 인덱싱된 필드가 중복 값을 저장하지 않도록 합니다. 즉, 인덱싱된 필드에 고유성을 강제합니다. 기본적으로 MongoDB는 _id 필드 생성 시 고유 인덱스를 생성합니다.
참고
새로운 내부 형식
MongoDB 4.2부터는 eatureCompatibilityVersion (fCV)이 4.2 이상인 경우, 이전 MongoDB 버전과 호환되지 않는 고유 인덱스에 대해 새로운 내부 형식을 사용합니다. 새로운 형식은 기존 고유 인덱스와 새로 생성되거나 재구축된 고유 인덱스 모두에 적용됩니다.
MongoDB Atlas에서 호스팅되는 배포서버에 대해 UI에서 고유 인덱스를 생성하고 관리할 수 있습니다.
고유 색인 만들기
고유 인덱스를 생성하려면 true
로 설정된 unique
옵션이 있는 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 } )
고유 복합 인덱스
복합 인덱스에 대해서도 고유 제약 조건을 적용할 수 있습니다. 복합 인덱스에 고유 제약 조건을 사용하는 경우, MongoDB는 인덱스 키 값 조합에 대한 고유성을 강제합니다.
예를 들어 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()
를 발행하세요.
개별 문서에 걸친 고유 제약 조건
고유 제약 조건은 컬렉션의 개별 문서에 적용됩니다. 즉, 고유 인덱스는 별도의 문서가 인덱스된 키에 대해 동일한 값을 갖는 것을 방지합니다.
제약 조건은 개별 문서에 적용되므로 고유한 멀티키 인덱스의 경우 문서에 배열 요소를 가질 수 있으며, 해당 문서의 인덱스 키 값이 다른 문서의 인덱스 키 값과 중복되지 않는 한 인덱스 키 값이 반복될 수 있습니다. 이 경우 반복되는 인덱스 항목은 인덱스에 한 번만 삽입됩니다.
예를 들어 다음 문서가 있는 컬렉션을 생각해 보겠습니다.
{ _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
값을 포함하는 하나의 문서만 포함할 수 있습니다. 인덱스 항목에 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 }" } })
고유 복합 인덱스에서 문서 필드가 누락됨
고유 복합 인덱스에서 하나 이상의 인덱스된 필드에 대해 문서가 null
값을 가지거나 값이 누락된 경우, 인덱스는 문서의 인덱스 항목에서 각 null
또는 누락된 필드에 대해 null 값을 저장합니다. 고유한 제약 조건으로 인해 고유한 복합 인덱스는 인덱스 항목의 모든 인덱스 필드에 대해 null
값을 가진 문서 하나만 허용합니다. 모든 인덱싱된 필드에 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 } } } )
고유 부분 인덱스
버전 3.2에 새로 추가되었습니다.
부분 인덱스는 지정된 필터 표현식을 충족하는 컬렉션의 문서만 인덱싱합니다. partialFilterExpression
과(와) 고유 제약 조건을 모두 지정하는 경우 고유 제약 조건은 필터 표현식을 충족하는 문서에만 적용됩니다.
고유 제약 조건이 있는 부분 인덱스는 문서가 필터 기준을 충족하지 않는 경우 고유 제약 조건을 충족하지 않는 문서의 삽입을 막지 않습니다. 이에 대한 예시는 고유 제약 조건이 있는 부분 인덱스를 참조하세요.
샤딩된 클러스터와 고유 인덱스
해시 인덱스에는 고유한 제약 조건을 지정할 수 없습니다.
범위가 지정된 샤딩된 컬렉션의 경우 다음 인덱스만 고유할 수 있습니다.
인덱스가 될 수 있습니다.
인덱스는 기본
_id
인덱스입니다. 그러나_id
인덱스는_id
필드가 샤드 키 또는 샤드 키의 접두사가 아닌 경우에만 샤드별 고유성 제약 조건을 집행합니다.중요
고유성 및 _id 인덱스
_id
필드가 샤드 키 또는 샤드 키의 접두사가 아닌 경우_id
인덱스는 샤드 전체가 아닌 샤드당 고유성 제약 조건만 집행합니다.예를 들어, 샤드 키
{x: 1}
로 두 샤드 A와 B에 걸쳐 있는 샤드된 컬렉션을 생각해 보십시오._id
키는 샤드 키의 일부가 아니므로 컬렉션에는 샤드 A에_id
값이1
인 문서가 있고, 샤드 B에_id
값이1
인 또 또 다른 문서가 있을 수 있습니다._id
필드가 샤드 키가 아니거나 샤드 키의 접두사가 아닌 경우, MongoDB는 애플리케이션이_id
값의 고유성을 샤드 전체에 걸쳐 집행할 것으로 예상합니다.
고유한 인덱스 제약 조건은 다음을 의미합니다.
샤딩할 collection의 경우 collection에 다른 고유 인덱스가 있으면 collection을 샤딩할 수 없습니다.
이미 샤딩된 collection의 경우 다른 필드에 고유 인덱스를 만들 수 없습니다.
샤드 키 가 아닌 필드 에서 고유성을 유지하려면 임의 필드에 대한 고유 제약 조건을 참조하세요.
희소 및 비희소 고유 인덱스
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 } )
기본 및 희소 인덱스 생성
sparse 옵션을 사용하거나 사용하지 않고 동일한 키 패턴으로 기본 인덱스를 생성할 수도 있습니다.
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 } )