MongoDB에서 중복 항목을 방지하는 이유와 방법
데이터베이스를 운영하다 보면 동일한 값이 여러 번 저장되는 중복 데이터 문제를 자주 마주하게 됩니다. 예를 들어 사용자 이름(UserName)처럼 고유해야 하는 필드에 같은 값이 반복해서 입력되면, 이후 조회·집계 로직에서 오류나 혼란을 일으킬 수 있습니다.
다행히 MongoDB는 createIndex() 메서드에 unique: true 옵션을 지정하는 것만으로 간단하게 중복 입력을 차단할 수 있습니다. 이 글에서는 실제 예제와 함께 그 과정을 단계별로 살펴보겠습니다.
1. 유니크 인덱스 생성하기
중복을 막고 싶은 필드에 대해 다음과 같은 문법으로 유니크 인덱스를 생성합니다.
db.컬렉션명.createIndex({"필드명":1},{unique:true});실제로 avoidDuplicateEntriesDemo 컬렉션의 UserName 필드에 유니크 인덱스를 적용해 보겠습니다.
> db.avoidDuplicateEntriesDemo.createIndex({"UserName":1},{unique:true});
{
"createdCollectionAutomatically" : true,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}출력 결과를 보면 컬렉션이 자동으로 생성되었고(createdCollectionAutomatically: true), 인덱스가 기본 _id 인덱스 1개에서 2개로 늘어난 것을 확인할 수 있습니다.
2. 첫 번째 문서 삽입 — 정상 처리
인덱스가 준비되었으니 문서를 하나 삽입해 보겠습니다.
> db.avoidDuplicateEntriesDemo.insertOne({"UserName":"John"});
{
"acknowledged" : true,
"insertedId" : ObjectId("5c90e1824afe5c1d2279d697")
}처음 삽입되는 "John" 값은 인덱스에 존재하지 않으므로 정상적으로 저장됩니다.
3. 동일한 값 재삽입 시 발생하는 오류
이제 똑같은 값을 한 번 더 삽입하면 어떻게 될까요? MongoDB는 즉시 쓰기를 거부하고 E11000 중복 키 오류를 반환합니다.
> db.avoidDuplicateEntriesDemo.insertOne({"UserName":"John"});
2019-03-19T18:03:08.465+0530 E QUERY [js] WriteError: E11000 duplicate key error collection: test.avoidDuplicateEntriesDemo index: UserName_1 dup key: { : "John" } :
WriteError({
"index" : 0,
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: test.avoidDuplicateEntriesDemo index: UserName_1 dup key: { : \"John\" }",
"op" : {
"_id" : ObjectId("5c90e1844afe5c1d2279d698"),
"UserName" : "John"
}
})
WriteError@src/mongo/shell/bulk_api.js:461:48
Bulk/mergeBatchResults@src/mongo/shell/bulk_api.js:841:49
Bulk/executeBatch@src/mongo/shell/bulk_api.js:906:13
Bulk/this.execute@src/mongo/shell/bulk_api.js:1150:21
DBCollection.prototype.insertOne@src/mongo/shell/crud_api.js:252:9
@(shell):1:1오류 메시지의 핵심은 code: 11000입니다. 애플리케이션 코드에서는 이 에러 코드를 감지해 사용자에게 "이미 존재하는 이름입니다" 같은 안내를 제공하거나, 업데이트(upsert) 로직으로 전환하는 처리를 할 수 있습니다.
4. 다른 값은 정상적으로 삽입됨
유니크 제약은 동일한 값에만 적용되므로, 새로운 값은 문제없이 저장됩니다.
> db.avoidDuplicateEntriesDemo.insertOne({"UserName":"Carol"});
{
"acknowledged" : true,
"insertedId" : ObjectId("5c90e18d4afe5c1d2279d699")
}5. find()로 최종 결과 확인하기
find() 메서드로 컬렉션의 모든 문서를 조회해 보겠습니다.
> db.avoidDuplicateEntriesDemo.find();
실행 결과는 다음과 같습니다.
{ "_id" : ObjectId("5c90e1824afe5c1d2279d697"), "UserName" : "John" }
{ "_id" : ObjectId("5c90e18d4afe5c1d2279d699"), "UserName" : "Carol" }결과를 보면 "John"은 한 번만 저장되어 있고, "Carol"은 정상적으로 추가된 것을 확인할 수 있습니다.
정리 및 추가 팁
- 핵심 문법:
createIndex({"필드명":1}, {unique:true})로 해당 필드의 중복을 원천 차단합니다. - 오류 코드 11000: 중복 키 오류가 발생했음을 의미하며, 애플리케이션에서 이를 활용해 예외 처리를 구현할 수 있습니다.
- 기존 데이터 주의: 이미 중복된 값이 있는 컬렉션에 유니크 인덱스를 생성하면 실패하므로, 먼저 중복 데이터를 정리해야 합니다.
- 부분 유니크 인덱스: 특정 조건을 만족하는 문서에만 유니크 제약을 적용하고 싶다면
partialFilterExpression옵션을 활용할 수 있습니다.
이처럼 유니크 인덱스 하나만 잘 활용해도 데이터 무결성을 크게 높일 수 있습니다. 이메일, 사용자 ID, 주문 번호 등 고유성이 보장되어야 하는 모든 필드에 적용해 보시기 바랍니다.