중복 Mongo ObjectId가 두 개의 다른 컬렉션에서 생성 될 가능성이 있습니까?
두 개의 다른 콜렉션에있는 문서에 대해 동일한 정확한 Mongo ObjectId를 생성 할 수 있습니까? 나는 그것이 매우 가능성이 거의 없다는 것을 알고 있지만 가능합니까?
내가 구체적으로 묻지 않은 이유는 내가 작업하는 응용 프로그램을 사용하여 우리 사이트의 본격적인 사용자로 전환하려는 선출 된 공무원의 공개 프로필을 보여주기 때문입니다. 현재 당사 사이트의 회원이 아닌 사용자와 선출 된 공무원을위한 별도의 컬렉션이 있습니다. 선출 된 공무원에 대한 다양한 데이터가 포함 된 다양한 다른 문서가 있으며, 모두 선출 된 공식 ObjectId를 사용하여 사람에게 다시 매핑됩니다.
계정을 만든 후에도 선출 된 공무원과 관련된 데이터를 계속 강조하지만 이제 해당 사용자 ObjectId를 가진 사용자 컬렉션의 일부로 프로필을 응용 프로그램과의 상호 작용에 매핑합니다.
몇 달 전에 응용 프로그램을 MySql에서 Mongo로 변환하기 시작했으며 전환하는 동안 이러한 데이터 유형 모두에 대한 레거시 MySql ID를 저장하고 선택한 공식 Mongo ObjectId를 사용자에게 저장하기 시작했습니다. 선출 된 공식 데이터에 다시 매핑 할 문서.
새로운 사용자 ObjectId를 이전에 선택된 공식 ObjectId로 지정하여 일을 단순화하기 위해 고민했지만 기존 사용자 ObjectId와 충돌 할 수 없도록하고 싶었습니다.
통찰력 주셔서 감사합니다.
편집 :이 질문을 게시 한 직후 제안 된 솔루션이 그리 좋지 않다는 것을 깨달았습니다. 현재 스키마를 유지하고 사용자 문서에서 선출 된 공식 '_id'에 연결하는 것이 좋습니다.
짧은 답변
초기 질문에 대한 직접적인 응답을 추가하기 만하면됩니다. 그렇습니다. BSON Object ID 생성을 사용하는 경우 대부분의 드라이버 에서 ID는 컬렉션 전체에서 고유해야합니다. "거의 확실히"의 의미는 아래를 참조하십시오.
긴 답변
Mongo DB 드라이버가 생성 한 BSON 오브젝트 ID는 콜렉션 전체에서 고유 할 가능성이 높습니다. 이는 주로 ID의 마지막 3 바이트로 인해 발생 하며 대부분의 드라이버 에서 정적 증분 카운터를 통해 생성됩니다. 이 카운터는 컬렉션 독립적입니다. 그것은 세계적입니다. 예를 들어 Java 드라이버는 임의로 초기화 된 정적 AtomicInteger를 사용합니다.
그렇다면 몽고 문서에서 왜 ID가 고유 할 것이라고 말하는 대신 ID가 고유 할 가능성이 높다고 말하는가? 고유 ID를 얻지 못할 경우 세 가지 가능성이 발생할 수 있습니다 (추가 정보가 있으면 알려주세요).
이 논의 전에 BSON 오브젝트 ID가 다음으로 구성되어 있음을 기억하십시오.
[에포크 이후 4 바이트, 3 바이트 머신 해시, 2 바이트 프로세스 ID, 3 바이트 카운터]
다음 세 가지 가능성이 있으므로 속임수를받을 가능성이 있는지 스스로 판단하십시오.
1) 카운터 오버 플로우 : 카운터에 3 바이트가 있습니다. 동일한 시스템에서 동일한 프로세스에서 1 초에 16,777,216 (2 ^ 24) 이상의 문서를 삽입하는 경우 증분 카운터 바이트가 오버 플로우되고 동일한 시간을 공유하는 두 개의 오브젝트 ID가 생길 수 있습니다. , 프로세스 및 카운터 값.
2) 카운터 비 증분 : 일부 Mongo 드라이버는 카운터 바이트의 숫자를 증가시키는 대신 임의의 숫자를 사용합니다. 이 경우 고유하지 않은 ID를 생성 할 수있는 1 / 16,777,216의 기회가 있지만 두 ID가 동일한 초에 생성 된 경우 (즉, ID의 시간 섹션이 다음 초로 업데이트되기 전에) 동일한 과정에서 기계.
3) 기계 및 프로세스 해시가 동일한 값으로 설정됩니다. 가능성이 거의없는 시나리오에서 시스템 ID 및 프로세스 ID 값은 서로 다른 두 시스템에 대해 동일한 값으로 맵핑 될 수 있습니다. 이 문제가 발생하고 동시에 다른 두 컴퓨터의 두 카운터가 동일한 초 동안 동일한 값을 생성하면 중복 ID가 생깁니다.
다음은주의해야 할 세 가지 시나리오입니다. 시나리오 1과 3은 가능성이 거의 없으며 올바른 드라이버를 사용하는 경우 시나리오 2를 완전히 피할 수 있습니다. 확실하게 드라이버의 소스를 확인해야합니다.
ObjectId는 UUID와 비슷한 방식으로 클라이언트 측에서 생성되지만 순서가 거의 증가하고 작성 시간을 무료로 인코딩하는 등 데이터베이스에 저장하기에 더 좋은 특성을 갖습니다. 사용 사례의 핵심은 다른 시스템에서 생성 되더라도 높은 확률로 고유성을 보장하도록 설계되었다는 것입니다.
이제 _id 필드를 일반적으로 언급한다면 컬렉션 전체에서 고유성을 요구하지 않으므로 이전 _id를 재사용하는 것이 안전합니다. 두 개의 컬렉션을 가지고있는 경우 구체적인 예로서, colors
그리고 fruits
모두가 동시에 같은 개체를 가질 수있다 {_id: 'orange'}
.
ObjectId 작성 방법에 대한 자세한 내용은 다음 사양을 참조하십시오 . http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-BSONObjectIDSpecification
누군가 Mongo ObjectID 복제에 문제가있는 경우 Mongo 자체에서 Dups가 발생할 가능성은 없지만 Mongo에서 PHP로 중복 _id를 생성 할 수 있음을 알아야합니다.
이것이 정기적으로 일어난 유스 케이스는 데이터 세트를 반복하고 데이터를 컬렉션에 주입하려고 할 때입니다.
주입 데이터를 보유하는 배열은 _id 값을 지정하지 않더라도 각 반복마다 명시 적으로 재설정해야합니다. 어떤 이유로 든 INSERT 프로세스는 Mongo _id를 배열이 전역 변수 인 것처럼 배열에 추가합니다 (배열에 전역 범위가없는 경우에도). 이것은 일반적으로 배열의 값이 호출 함수로 다시 유지되지 않을 것으로 예상되는 별도의 함수 호출에서 삽입을 호출하는 경우에도 영향을 줄 수 있습니다.
이에 대한 세 가지 해결책이 있습니다.
unset()
배열에서 _id 필드를 사용할 수 있습니다array()
데이터 세트를 반복 할 때마다 전체 배열을 다시 초기화 할 수 있습니다- _id 값을 명시 적으로 정의 할 수 있습니다 (딥을 생성하지 않는 방식으로 값을 정의하도록주의하십시오).
내 생각에 이것은 PHP 인터페이스의 버그이며 Mongo의 문제는 아니지만이 문제가 발생하면 _id를 설정 해제하면 괜찮을 것입니다.
컬렉션 간 ObjectId 고유성에 대해 어떠한 보장도하지 않습니다. 비록 확률 적으로 매우 가능성이 낮더라도 컬렉션 전체에서 _id 고유성에 의존하는 매우 열악한 응용 프로그램 디자인 일 것입니다.
mongo shell에서 이것을 쉽게 테스트 할 수 있습니다 :
MongoDB shell version: 1.6.5
connecting to: test
> db.foo.insert({_id: 'abc'})
> db.bar.insert({_id: 'abc'})
> db.foo.find({_id: 'abc'})
{ "_id" : "abc" }
> db.bar.find({_id: 'abc'})
{ "_id" : "abc" }
> db.foo.insert({_id: 'abc', data:'xyz'})
E11000 duplicate key error index: test.foo.$_id_ dup key: { : "abc" }
So, absolutely don't rely on _id's being unique across collections, and since you don't control the ObjectId generation function, don't rely on it.
It's possible to create something that's more like a uuid, and if you do that manually, you could have some better guarantee of uniqueness.
Remember that you can put objects of different "types" in the same collection, so why not just put your two "tables" in the same collection. They would share the same _id space, and thus, would be guaranteed unique. Switching from "prospective" to "registered" would be a simple flipping of a field...
'development' 카테고리의 다른 글
XMLHttpRequest의 응답을 얻는 방법? (0) | 2020.05.28 |
---|---|
이 루비 코드에서 (단항) * 연산자는 무엇을합니까? (0) | 2020.05.28 |
마크 다운 및 여러 파일 포함 (0) | 2020.05.28 |
Android 앱은 제거 및 재설치 후 데이터를 기억합니다 (0) | 2020.05.28 |
Vue.js의 URL에서 쿼리 매개 변수를 얻으려면 어떻게해야합니까? (0) | 2020.05.28 |