Computer >> 컴퓨터 >  >> 프로그래밍 >> MongoDB

MongoDB에서 여러 필드의 중복 데이터 방지 방법: 복합 유니크 인덱스 완벽 가이드

MongoDB에서 여러 필드 조합의 중복 방지하기

데이터베이스를 운영하다 보면 단일 필드가 아닌 여러 필드의 조합이 중복되지 않도록 관리해야 하는 경우가 자주 발생합니다. 예를 들어, 같은 이름의 사용자가 서로 다른 과목을 수강하는 것은 허용하되, 동일한 사용자가 같은 과목을 중복 등록하는 것은 막고 싶은 상황을 생각해볼 수 있습니다.

MongoDB에서는 ensureIndex() 메서드(최신 버전에서는 createIndex())에 unique: true 옵션을 설정하여 이러한 요구사항을 손쉽게 구현할 수 있습니다.

1. 복합 유니크 인덱스 생성

먼저 컬렉션을 생성하면서 FirstNameSubject 두 필드에 대한 복합 유니크 인덱스를 만들어 보겠습니다.

> db.demo272.ensureIndex({"FirstName":1,"Subject":1},{unique:true});
{
    "createdCollectionAutomatically" : true,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

인덱스가 정상적으로 생성되면 위와 같이 인덱스 개수가 1개에서 2개로 증가한 것을 확인할 수 있습니다. 이제 해당 컬렉션에는 FirstName과 Subject의 조합이 동일한 문서는 저장될 수 없습니다.

2. 문서 삽입 테스트

유니크 제약 조건이 실제로 작동하는지 몇 가지 문서를 삽입해 보겠습니다.

> db.demo272.insertOne({"FirstName":"Chris","Subject":"MySQL"});
{
    "acknowledged" : true,
    "insertedId" : ObjectId("5e48232a1627c0c63e7dbabf")
}
> db.demo272.insertOne({"FirstName":"Chris","Subject":"MongoDB"});
{
    "acknowledged" : true,
    "insertedId" : ObjectId("5e48232f1627c0c63e7dbac0")
}
> db.demo272.insertOne({"FirstName":"David","Subject":"MySQL"});
{
    "acknowledged" : true,
    "insertedId" : ObjectId("5e48233a1627c0c63e7dbac1")
}

위 세 건의 삽입은 모두 성공했습니다. Chris가 MySQL과 MongoDB라는 서로 다른 과목을 각각 등록했고, David도 MySQL을 등록했기 때문에 필드 조합이 모두 다르기 때문입니다.

3. 중복 삽입 시 에러 확인

이제 이미 존재하는 조합인 Chris + MySQL을 다시 삽입해 보겠습니다.

> db.demo272.insertOne({"FirstName":"Chris","Subject":"MySQL"});
2020-02-15T22:28:55.137+0530 E QUERY    [js] WriteError: E11000 duplicate key error collection: test.demo272 index: FirstName_1_Subject_1 dup key: { : "Chris", : "MySQL" } :
WriteError({
    "index" : 0,
    "code" : 11000,
    "errmsg" : "E11000 duplicate key error collection: test.demo272 index: FirstName_1_Subject_1 dup key: { : \"Chris\", : \"MySQL\" }",
    "op" : {
        "_id" : ObjectId("5e48234f1627c0c63e7dbac2"),
        "FirstName" : "Chris",
        "Subject" : "MySQL"
    }
})
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

예상대로 E11000 duplicate key error가 발생하며 삽입이 거부되었습니다. 에러 메시지를 살펴보면 FirstName_1_Subject_1 인덱스에서 { "Chris", "MySQL" } 키가 중복되었다는 것을 명확히 알려줍니다. 이처럼 MongoDB는 유니크 인덱스를 통해 데이터 무결성을 자동으로 보호합니다.

4. 저장된 문서 조회

find() 메서드를 사용해 컬렉션에 저장된 모든 문서를 확인해 보겠습니다.

> db.demo272.find();

실행 결과는 다음과 같습니다.

{ "_id" : ObjectId("5e48232a1627c0c63e7dbabf"), "FirstName" : "Chris", "Subject" : "MySQL" }
{ "_id" : ObjectId("5e48232f1627c0c63e7dbac0"), "FirstName" : "Chris", "Subject" : "MongoDB" }
{ "_id" : ObjectId("5e48233a1627c0c63e7dbac1"), "FirstName" : "David", "Subject" : "MySQL" }

중복으로 삽입하려 했던 문서는 저장되지 않았고, 유효한 3건의 문서만 남아 있는 것을 확인할 수 있습니다.

정리 및 핵심 포인트

  • 복합 유니크 인덱스: ensureIndex({필드1: 1, 필드2: 1}, {unique: true}) 형태로 여러 필드의 조합에 대한 고유성을 강제할 수 있습니다.
  • E11000 에러 코드: 중복 키 오류가 발생하면 MongoDB는 코드 11000번 에러를 반환하므로, 애플리케이션에서 이를 감지해 적절히 처리할 수 있습니다.
  • createIndex() 권장: ensureIndex()는 현재 deprecated(더 이상 권장되지 않음)된 메서드이므로, 최신 MongoDB 버전에서는 동일하게 동작하는 createIndex()를 사용하는 것이 좋습니다.

이 방식을 활용하면 회원 ID와 이메일 조합, 주문 번호와 상품 조합 등 다양한 비즈니스 로직에서 데이터 중복 문제를 효과적으로 예방할 수 있습니다.