AI 에이전트의 경우: 문서 인덱스는 https://www.mongodb.com/ko-kr/docs/llms.txt에서 사용할 수 있으며, 모든 페이지의 마크다운 버전은 어떤 URL 경로에 .md를 추가하여 사용할 수 있습니다.
Docs Menu

고유 인덱스 및 스키마 유효성 검사

데이터베이스 애플리케이션 설계에 부합하도록 하려면 전략적인 인덱스를 생성하여 인덱스 속성과 스키마 유효성 검사 결합할 수 있습니다.

사용자의 재정을 요약하는 애플리케이션 예로 들어 보겠습니다. 애플리케이션 의 메인 페이지에는 사용자의 ID 와 애플리케이션 과 동기화된 모든 은행 계정의 잔액이 표시됩니다.

애플리케이션 사용자 정보를 users 컬렉션 에 저장합니다. users 컬렉션 에는 다음 스키마 가진 문서가 포함되어 있습니다.

db.users.insertOne( {
_id: 1,
name: { first: "john", last: "smith" },
accounts: [
{ balance: 500, bank: "abc", number: "123" },
{ balance: 2500, bank: "universal bank", number: "9029481" }
]
} )

애플리케이션 다음 규칙이 필요합니다.

  • 사용자는 애플리케이션 에 등록할 수 있지만 은행 계좌를 동기화 수는 없습니다.

  • 사용자는 bank 및 number 필드로 계정을 식별합니다.

  • 사용자는 서로 다른 두 사용자에 대해 동일한 계정을 등록할 수 없습니다.

  • 사용자는 동일한 사용자에 대해 동일한 계정을 여러 번 등록할 수 없습니다.

문서를 애플리케이션의 규칙에 따라 제한하도록 데이터베이스 설계하려면 다음 절차에 따라 데이터베이스 에서 고유 인덱스 와 스키마 유효성 검사 결합합니다.

1

애플리케이션의 규칙을 시행하다 하려면 다음 특성을 가진 accounts.bank 및 accounts.number 필드에 인덱스 생성합니다.

  • bank 및 number 필드가 반복되지 않도록 하려면 인덱스 고유하게만듭니다.

  • 여러 필드의 인덱싱 허용하려면 인덱스를 복합 인덱스로 만듭니다.

  • 배열 내부의 문서에 대한 인덱싱 허용하려면 유형의 인덱스 멀티키로 만듭니다.

따라서 다음 사양 및 옵션을 사용하여 복합 멀티키 고유 인덱스 생성합니다.

const specification = { "accounts.bank": 1, "accounts.number": 1 };
const options = { name: "Unique Account", unique: true };
db.users.createIndex(specification, options); // Unique Account
2

현재 상태 의 인덱스 모든 문서를 인덱싱합니다. 그러나 이 구현 accounts.bank 또는 accounts.number 필드가 누락된 문서를 삽입할 때 오류가 발생할 수 있습니다.

예시 들어 users 컬렉션 에 다음 데이터를 삽입해 봅니다.

const user1 = { _id: 1, name: { first: "john", last: "smith" } };
const user2 = { _id: 2, name: { first: "john", last: "appleseed" } };
const account1 = { balance: 500, bank: "abc", number: "123" };
db.users.insertOne(user1);
db.users.insertOne(user2);
{ acknowledged: true, insertedId: 1 }
MongoServerError: E11000 duplicate key error collection: test.users index: Unique Account dup key: { accounts.bank: null, accounts.number: null }

지정된 필드가 하나 이상 누락된 문서 인덱싱된 컬렉션 에 삽입하려고 하면 MongoDB 다음을 수행합니다.

  • 삽입된 문서 에 누락된 필드를 채웁니다.

  • 값을 다음으로 설정합니다. null

  • 인덱스 에 항목을 추가합니다.

accounts.bank 및 accounts.number 필드 없이 user1 을(를) 삽입하면 MongoDB 해당 필드를 null (으)로 설정하고 고유 인덱스 항목을 추가합니다. user2와 같이 두 필드 하나도 없는 나중에 삽입하면 중복 키 오류가 발생합니다.

이를 방지하려면 부분 필터하다 표현식 사용하여 인덱스 두 필드가 모두 포함된 문서만 포함되도록 합니다. 자세한 내용은 고유 제약 조건이 있는 부분 인덱스를 참조하세요. 다음 옵션을 사용하여 인덱스 다시 생성합니다.

const specification = { "accounts.bank": 1, "accounts.number": 1 };
const optionsV2 = {
name: "Unique Account V2",
partialFilterExpression: {
"accounts.bank": { $exists: true },
"accounts.number": { $exists: true }
},
unique: true
};
db.users.drop( {} ); // Delete previous documents and indexes definitions
db.users.createIndex(specification, optionsV2); // Unique Account V2

accounts.bank 및 accounts.number 필드를 포함하지 않는 두 명의 사용자를 삽입하여 새 인덱스 정의를 테스트합니다.

db.users.insertOne(user1);
db.users.insertOne(user2);
{ acknowledged: true, insertedId: 1 }
{ acknowledged: true, insertedId: 2 }
3

서로 다른 두 사용자에 대해 동일한 계정을 등록할 수 없도록 다음 코드를 테스트합니다.

/* Cleaning the collection */
db.users.deleteMany( {} ); // Delete only documents, keep indexes definitions
db.users.insertMany( [user1, user2] );
/* Test */
db.users.updateOne( { _id: user1._id }, { $push: { accounts: account1 } } );
db.users.updateOne( { _id: user2._id }, { $push: { accounts: account1 } } );
{ acknowledged: true, insertedId: null, matchedCount: 1, modifiedCount: 1, upsertedCount: 0 }
MongoServerError: E11000 duplicate key error collection: test.users index: Unique Account V2 dup key: { accounts.bank: "abc", accounts.number: "123" }

두 번째 updateOne 명령은 두 명의 개별 사용자에 대해 동일한 계정을 추가할 수 없으므로 오류를 올바르게 반환합니다.

데이터베이스 동일한 사용자에 대해 동일한 계정을 여러 번 추가할 수 없는지 테스트합니다.

/* Cleaning the collection */
db.users.deleteMany( {} ); // Delete only documents, keep indexes definitions
db.users.insertMany( [user1, user2] ); // Re-insert test documents
/* Test */
db.users.updateOne( { _id: user1._id }, { $push: { accounts: account1 } } );
db.users.updateOne( { _id: user1._id }, { $push: { accounts: account1 } } );
db.users.findOne( { _id: user1._id } );
{ acknowledged: true, insertedIds: { '0': 1, '1': 2 } }
{ acknowledged: true, insertedId: null, matchedCount: 1, modifiedCount: 1, upsertedCount: 0 }
{ acknowledged: true, insertedId: null, matchedCount: 1, modifiedCount: 1, upsertedCount: 0 }
_id: 1,
name: { first: 'john', last: 'smith' },
accounts: [
{ balance: 500, bank: 'abc', number: '123' },
{ balance: 500, bank: 'abc', number: '123' }
]

반환된 코드는 데이터베이스 동일한 사용자에게 동일한 계정을 여러 번 잘못 추가했음을 보여줍니다. 이 오류는 MongoDB 인덱스가 동일한 문서 를 가리키는 동일한 키 값을 가진 완전히 동일한 항목을 복제하지 않기 때문에 발생합니다.

사용자에게 account1 를 두 번째로 삽입하면 MongoDB 인덱스 항목 생성하지 않으므로 중복 값이 없습니다. 애플리케이션 디자인을 효과적으로 구현 하려면 동일한 사용자에게 동일한 계정을 여러 번 추가하려고 시도하는 경우 데이터베이스 오류를 반환해야 합니다.

4

애플리케이션 동일한 사용자에게 동일한 계정을 여러 번 추가하는 것을 거부하도록 하려면 스키마 유효성 검사 구현 . 다음 코드에서는 $expr 연산자 사용하여 배열 내의 항목이 고유한지 확인하는 표현식 쓰기 (write) .

const accountsSet = {
$setIntersection: {
$map: {
input: "$accounts",
in: { bank: "$$this.bank", number: "$$this.number" }
}
}
};
const uniqueAccounts = {
$eq: [ { $size: "$accounts" }, { $size: accountsSet } ]
};
const accountsValidator = {
$expr: {
$cond: {
if: { $isArray: "$accounts" },
then: uniqueAccounts,
else: true
}
}
};

{ $isArray: "$accounts" } 가 true이면 문서 에 accounts 배열 존재하며 MongoDB uniqueAccounts 유효성 검사 검사 로직을 적용합니다. 문서 로직을 통과하면 유효합니다.

uniqueAccounts 표현식 원래 accounts 배열 의 크기를 accountsSet 의 $setIntersection 매핑된 버전의 에 의해 생성된 의 크기와 accounts 비교합니다.

  • $map 함수는 accounts.bank 및 accounts.number 필드만 포함하도록 accounts 배열 의 각 항목을 변환합니다.

  • $setIntersection 함수는 매핑된 배열 설정하다 으로 처리하여 중복을 제거합니다.

  • $eq 함수는 원본 accounts 배열 과 중복 제거된 accountsSet 배열의 크기를 비교합니다.

두 크기가 동일하고 모든 항목이 accounts.bank 및 accounts.number로 고유한 경우 유효성 검사 true를 반환합니다. 그렇지 않은 경우 중복이 존재하며 오류와 함께 유효성 검사 실패합니다.

스키마 유효성 검사 검사를 테스트하여 데이터베이스 동일한 사용자에게 동일한 계정을 여러 번 추가하는 것을 허용하지 않는지 확인할 수 있습니다.

/* Cleaning the collection */
db.users.drop( {} ); // Delete documents and indexes definitions
db.runCommand( {
collMod: "users", // update collection to use schema validation
validator: accountsValidator
} );
db.users.insertMany( [user1, user2] );
/* Test */
db.users.updateOne( { _id: user1._id }, { $push: { accounts: account1 } } );
db.users.updateOne( { _id: user1._id }, { $push: { accounts: account1 } } );
MongoServerError: Document failed validation
Additional information: {
failingDocumentId: 1,
details: {
operatorName: '$expr',
specifiedAs: {
'$expr': {
'$cond': {
if: { '$and': '$accounts' },
then: { '$eq': [ [Object], [Object] ] },
else: true
}
}
},
reason: 'expression did not match',
expressionResult: false
}
}

두 번째 updateOne() 명령은 Document failed validation 오류를 반환하며, 이는 데이터베이스 동일한 사용자에게 동일한 계정을 여러 번 추가하려는 시도를 거부했음을 나타냅니다.