MongoDB의 고유 인덱스
이 자습서에서는 고유 인덱스가 무엇인지, MongoDB에서 생성하는 방법을 포함하여 고유 인덱스에 대해 알아봅니다. 또한 MongoDB에서 사용자의 이메일을 고유하게 만드는 과정을 간략하게 설명합니다.
이 기사의 목차는 다음과 같습니다.
- MongoDB의 고유 인덱스
- MongoDB에서 고유 인덱스 생성
- MongoDB의 고유 인덱스 동작
- Mongoose로 고유한 이메일 확인
MongoDB의 고유 인덱스
고유 인덱스는 인덱싱된 필드에 중복 값이 포함되지 않도록 보장하여 인덱싱된 필드가 고유하도록 합니다. 컬렉션을 구성하는 동안 MongoDB는 기본적으로 _id
열에 고유 인덱스를 생성합니다.
db.collection.createIndex()
명령을 사용하여 unique
옵션이 true
로 설정된 고유 인덱스를 생성합니다.
db.collection.createIndex( <key and index type specification>, { unique: true } )
단일 필드의 고유 인덱스
mongosh
에서 다음 절차를 사용하여 members
컬렉션의 user_id
필드에 고유 인덱스를 구축합니다.
db.members.createIndex( { "user_id": 1 }, { unique: true } )
고유 복합 지수
복합 인덱스에서 고유한 제한을 부과할 수도 있습니다. 예를 들어 MongoDB는 복합 인덱스에 대한 고유 제약 조건을 사용하는 경우 인덱스 키 값을 결합할 때 고유성을 적용합니다.
mongosh
에서 다음 작업을 사용하여 members
컬렉션의 groupNumber
, lastname
및 firstname
필드에 고유 인덱스를 구축합니다.
db.members.createIndex( { groupNumber: 2, 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: 6 } ] },
{ _id: 3, a: [ { loc: "A", qty: 12 } ] }
] )
MongoDB의 고유 인덱스 동작
제한:
컬렉션에 인덱스의 고유 요구 사항을 위반하는 데이터가 이미 포함된 경우 MongoDB는 제공된 인덱스 필드에 고유한 인덱스를 설정할 수 없습니다. 해시 인덱스에서는 고유 제약 조건을 정의할 수 없습니다.
복제 세트 및 분할된 클러스터를 사용하여 고유 인덱스 생성
롤링 작업을 사용하여 복제 세트 및 분할된 클러스터에 고유 인덱스를 구축하려면 절차 전체에서 컬렉션에 대한 모든 쓰기를 중지해야 합니다.
절차 중에 컬렉션에 대한 모든 쓰기를 중지할 수 없는 경우 롤링 작업을 사용하지 마십시오. 대신 다음을 실행하여 컬렉션에 대한 고유한 인덱스를 만듭니다.
- 복제본 세트의 기본에서
db.collection.createIndex()
- 샤드 클러스터에 대한
mongos
의db.collection.createIndex()
개별 문서에 대한 고유 제약 조건
유일한 요구 사항은 컬렉션의 각 문서에 적용됩니다. 고유 인덱스는 인덱스 키가 다른 문서에서 동일한 값을 갖는 것을 방지합니다.
제한 사항은 별도의 문서에만 적용되기 때문에 문서의 인덱스 키 값이 다른 문서의 인덱스 키 값과 중복되지 않는 한 문서에는 고유한 다중 키 인덱스에 대한 인덱스 키 값을 반복하는 항목 배열이 있을 수 있습니다. 반복되는 색인 항목은 이 시나리오에서 한 번만 색인에 입력됩니다.
예를 들어 다음 문서를 포함하는 컬렉션입니다.
{ _id: 1, a: [ { loc: "A", qty: 6 }, { qty: 10 } ] }
{ _id: 2, a: [ { loc: "A" }, { qty: 7 } ] }
{ _id: 3, a: [ { loc: "A", qty: 12 } ] }
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 값을 저장합니다. MongoDB는 고유 제약 조건으로 인해 하나의 문서에만 인덱스 열이 누락되도록 허용합니다.
인덱싱된 필드에 대한 값이 없는 문서가 두 개 이상 있거나 인덱싱된 필드가 누락된 경우 중복 키 오류와 함께 인덱스 생성이 실패합니다.
예를 들어 컬렉션에는 x
에 대한 고유 인덱스가 있습니다.
db.collection.createIndex( { "x": 13 }, { unique: true } )
컬렉션에 x
필드가 누락된 문서가 아직 포함되어 있지 않은 경우 고유 색인을 통해 x
필드 없이 문서를 삽입할 수 있습니다.
db.collection.insertOne( { y: 2 } )
그러나 컬렉션에 x
필드가 없는 문서가 이미 있는 경우 x
필드가 없는 문서를 삽입하면 고유 인덱스가 실패합니다.
db.collection.insertOne( { z: 2 } )
필드 x
값에 대한 고유 제약 조건을 위반했기 때문에 작업에서 문서를 삽입하지 못했습니다.
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 12000,
"errmsg" : "E12000 duplicate key error index: test.collection.$a.b_1 dup key: { : null }"
}
})
고유 부분 색인
특정 필터 식과 일치하는 컬렉션의 문서만 부분 인덱스에서 인덱싱됩니다. 따라서 partialFilterExpression
과 고유 제약 조건을 모두 사용하는 경우 고유 제약 조건은 필터 식과 일치하는 문서에만 적용됩니다.
문서가 필터 요구 사항을 충족하지 않는 경우 고유 제약 조건이 있는 부분 인덱스는 고유 제약 조건을 충족하지 않는 문서의 삽입을 금지하지 않습니다.
샤드 클러스터 및 고유 인덱스
해시 인덱스에서는 고유 제약 조건을 정의할 수 없습니다.
다음 인덱스만 범위 분할된 컬렉션에서 고유할 수 있습니다.
- 샤드 키의 인덱스 값.
- 분할 키로 접두사가 있는 복합 인덱스.
- 기본
_id
인덱스 그러나_id
인덱스는_id
필드가 샤드 키 또는 샤드 키 접두사가 아닌 경우에만 샤드별 고유성 요구 사항을 적용합니다.
고유 인덱스 제약 조건은 다음을 의미합니다.
- 컬렉션에 샤딩할 컬렉션에 대한 다른 고유 인덱스가 있는 경우 컬렉션을 샤딩할 수 없습니다.
- 다른 필드에서 이미 샤딩된 컬렉션에 대한 고유 인덱스를 생성할 수 없습니다.
스파스 및 비스파스 고유 인덱스
MongoDB 5.0부터 단일 컬렉션은 동일한 키 패턴을 가진 고유한 스파스 인덱스와 비스파스 인덱스를 가질 수 있습니다.
고유하고 희소한 인덱스 생성
이 예에서는 키 패턴이 동일하고 sparse
선택 항목이 다른 여러 인덱스가 생성됩니다.
db.scores.createIndex( { score : 2 }, { name: "unique_index", unique: true } )
db.scores.createIndex( { score : 2 }, { name: "unique_sparse_index", unique: true, sparse: true } )
기본 및 희소 인덱스 생성
sparse
옵션을 사용하거나 사용하지 않고 동일한 키 패턴으로 간단한 인덱스를 구성할 수 있습니다.
db.scores.createIndex( { score : 2 }, { name: "sparse_index", sparse: true } )
db.scores.createIndex( { score : 2 }, { name: "basic_index" } )
기본 및 고유 인덱스의 중복 키 패턴
MongoDB 5.0을 사용하면 동일한 키 패턴을 가진 기본 인덱스와 고유 인덱스를 가질 수 있습니다. 키 패턴의 중복으로 인해 이미 인덱싱된 필드에 고유 인덱스를 추가할 수 있습니다.
예:
{ score: 2 }
키 패턴으로 기본 인덱스를 만들고 세 개의 문서를 삽입합니다.
db.scores.createIndex( { score : 1 }, { name: "basic_index" } )
db.scores.insert( { score : 1 } )
db.scores.insert( { score : 2 } )
db.scores.insert( { score : 4 } )
동일한 키 패턴 { 점수: 2 }
을 사용하여 고유 인덱스를 만듭니다.
db.scores.createIndex( { score : 2 }, { name: "unique_index", unique: true } )
중복된 score
문서를 삽입하려는 시도는 고유 인덱스로 인해 실패합니다.
db.scores.insert( { score : 4 } )
Mongoose로 고유한 이메일 확인
Mongoose를 사용하면 유효성 검사를 사용하여 데이터베이스에서 중복을 방지할 수 있습니다. 유효성 검사는 Schema
유형으로 정의되며 미들웨어입니다.
스키마에서 유효성 검사를 생성하거나 Mongooses의 기본 제공 유효성 검사를 사용할 수도 있습니다. 중복을 방지하려면 Mongoose에게 각 문서가 지정된 경로에 대해 고유한 값을 가져야 함을 알려주는 unique
속성을 사용하는 것이 좋습니다.
이 경우 이메일
에 MongoDB 고유 인덱스를 만드는 약어입니다.
인덱스가 생성되기를 기다리면 아래와 같이 몽구스의 프라미스 기반 이벤트 Model.init()
를 사용할 수 있습니다.
const User = mongoose.model('User', mongoose.Schema({
email: {type: String, required: true, match: /.+\@.+\..+/, unique: true}
}));
await User.create([
{email: 'gmail@google.com'}, {email: 'bill@microsoft.com'},
{email: 'test@gmail.com'}
]);
await User.init();
try {
await User.create({email: 'gmail@google.com'});
} catch (error) {
error.message; // 'E12000 duplicate key error...'
}
이 기사에서는 MongoDB의 고유 인덱스에 대해 자세히 설명합니다. 또한 결국 고유한 이메일의 유효성 검사는 MongoDB의 mongoose
에서 수행됩니다.