중복 Mongo ObjectId가 두 개의 다른 컬렉션에서 생성 될 가능성이 있습니까?


187

두 개의 다른 콜렉션에있는 문서에 대해 동일한 정확한 Mongo ObjectId를 생성 할 수 있습니까? 나는 그것이 매우 가능성이 거의 없다는 것을 알고 있지만 가능합니까?

내가 구체적으로 묻지 않은 이유는 내가 작업하는 응용 프로그램을 사용하여 우리 사이트의 본격적인 사용자로 전환하려는 선출 된 공무원의 공개 프로필을 보여주기 때문입니다. 현재 당사 사이트의 회원이 아닌 사용자와 선출 된 공무원을위한 별도의 컬렉션이 있습니다. 선출 된 공무원에 대한 다양한 데이터가 포함 된 다양한 다른 문서가 있으며, 모두 선출 된 공식 ObjectId를 사용하여 사람에게 다시 매핑됩니다.

계정을 만든 후에도 선출 된 공무원과 관련된 데이터를 계속 강조하지만 이제 해당 사용자 ObjectId를 가진 사용자 컬렉션의 일부로 프로필을 응용 프로그램과의 상호 작용에 매핑합니다.

몇 달 전에 응용 프로그램을 MySql에서 Mongo로 변환하기 시작했으며 전환하는 동안 이러한 데이터 유형 모두에 대한 레거시 MySql ID를 저장하고 선택한 공식 Mongo ObjectId를 사용자에게 저장하기 시작했습니다. 선출 된 공식 데이터에 다시 매핑 할 문서.

새로운 사용자 ObjectId를 이전에 선택된 공식 ObjectId로 지정하여 일을 단순화하기 위해 고민했지만 기존 사용자 ObjectId와 충돌 할 수 없도록하고 싶었습니다.

통찰력 주셔서 감사합니다.

편집 :이 질문을 게시 한 직후 제안 된 솔루션이 그리 좋지 않다는 것을 깨달았습니다. 현재 스키마를 유지하고 사용자 문서에서 선출 된 공식 '_id'에 연결하는 것이 좋습니다.



1
전에 그 페이지를 읽었습니다. 아이러니하게도 이전 답변에서 동일한 페이지에 실제로 연결되었습니다. 그리고 나는 "고유 할 확률이 상당히 높다"는 면책을 보았지만 컬렉션에 삽입되는 것이 확실하지 않다. 확실하지 않은 것은 ObjectId의 2 바이트 프로세스 ID 부분이 실제로 나타내는 것입니다. 컬렉션과 관련이있는 경우 다른 컬렉션의 동일한 컴퓨터에서 정확히 동시에 생성 된 두 개의 다른 문서간에 고유성이 있습니다.
Anthony Jack

1
2 바이트 프로세스 ID는 ObjectID를 생성하는 프로세스의 pid입니다. 예를 들어, 다음은 pymongo가 ObjectID를 생성하는 데 사용하는 코드입니다. github.com/mongodb/mongo-python-driver/blob/master/bson/…
mstearn

내가 만난 한 가지는 배치 삽입입니다. 나는 10k 개의 문서를 배치하고 카운터 부분이 매번 롤오버되어 매번 충돌합니다.
fawce

시간이 오래 걸렸지 만 10K 문서는 카운터를 롤오버하지 않습니다. 카운터 부분은 3 자리가 아닌 3 바이트입니다. 1600 만 개가 넘습니다.
Asya Kamsky 2018 년

답변:


318

짧은 답변

초기 질문에 대한 직접적인 응답을 추가하기 만하면됩니다. 그렇습니다. 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를 완전히 피할 수 있습니다. 확실하게 드라이버의 소스를 확인해야합니다.


3 바이트 카운터가 기계 당 프로세스 당 초당 삽입 된 2 ^ 24 = 16777216 개의 문서 수를 수용하는 기능을 나타내지 않습니까?
포레스트 예

당신은 절대적으로 맞습니다. 실수로 비트 수를 반으로 줄였습니다. 답변이 수정되었습니다.
Raj Advani 2019

난 그냥이 들어갔다 때문에, 내가 어떤 드라이버 (예 : C), 사용 증가하지만, 증가 원자, 수시로 때문에, 그것은 인종 상태로 동일한 OID를 생성하지 않는 추가 할 수 있습니다
파블 Veselov

39
136 년 동안 ObjectId머신 해시, 프로세스 ID 및 카운터가 모두 동일한 것으로 판명되는 한 이전과 동일한 샷을 생성 할 수 있다는 사실을 완전히 건너 뛰었습니다.
jamylak

25
@jamylak 우리는 그 문제가 시급해질 때 그 문제를 처리 할 것입니다 (70 년대 YYMMDD 날짜 형식을 표준화 한 사람들에게 말함)
Philipp

14

ObjectId는 UUID와 비슷한 방식으로 클라이언트 측에서 생성되지만 순서가 거의 증가하고 작성 시간을 무료로 인코딩하는 등 데이터베이스에 저장하기에 더 좋은 특성을 갖습니다. 사용 사례의 핵심은 다른 시스템에서 생성 된 경우에도 높은 확률로 고유성을 보장하도록 설계되었다는 것입니다.

이제 _id 필드를 일반적으로 언급한다면 컬렉션 전체에서 고유성을 요구하지 않으므로 이전 _id를 재사용하는 것이 안전합니다. 두 개의 컬렉션을 가지고있는 경우 구체적인 예로서, colors그리고 fruits모두가 동시에 같은 개체를 가질 수있다 {_id: 'orange'}.

ObjectId 작성 방법에 대한 자세한 내용은 다음 사양을 참조하십시오 . http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-BSONObjectIDSpecification


11

누군가 Mongo ObjectID 복제에 문제가있는 경우 Mongo 자체에서 Dups가 발생할 가능성은 없지만 Mongo에서 PHP로 중복 _id를 생성 할 수 있음을 알아야합니다.

이것이 정기적으로 일어난 유스 케이스는 데이터 세트를 반복하고 데이터를 컬렉션에 주입하려고 할 때입니다.

주입 데이터를 보유하는 배열은 _id 값을 지정하지 않더라도 각 반복마다 명시 적으로 재설정해야합니다. 어떤 이유로 든 INSERT 프로세스는 Mongo _id를 배열이 전역 변수 인 것처럼 배열에 추가합니다 (배열에 전역 범위가없는 경우에도). 일반적으로 배열의 값이 호출 함수로 다시 유지되지 않을 것으로 예상되는 별도의 함수 호출에서 삽입을 호출하는 경우에도 영향을 줄 수 있습니다.

이에 대한 세 가지 해결책이 있습니다.

  1. unset()배열에서 _id 필드를 사용할 수 있습니다
  2. array()데이터 세트를 반복 할 때마다 전체 배열을 다시 초기화 할 수 있습니다
  3. _id 값을 명시 적으로 정의 할 수 있습니다 (딥을 생성하지 않는 방식으로 값을 정의하도록주의하십시오).

내 생각에 이것은 PHP 인터페이스의 버그이며 Mongo의 문제는 아니지만이 문제가 발생하면 _id를 설정 해제하면 괜찮을 것입니다.


여기 참조 : php.net/manual/en/mongocollection.insert.php : "참고 : 매개 변수가 _id 키 또는 재산, 새로운 MongoId 인스턴스가 여기에 생성되고 할당 될 것이다이없는 경우이 특별한 행동이 의미하는 것은 아니다. . 매개 변수를 참조로 전달된다 "는 기능이 아니라 버그, 그렇게 될 운명이야
올리버 코닉

1
여기서 설명하는 시나리오를 이해하지 못합니다. 아마도 버그를 나타내는 코드를 보여줄 수 있습니까?
Mark Amery

-7

컬렉션 간 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" }

따라서 컬렉션 전체에서 고유 한 _id에 의존하지 말고 ObjectId 생성 기능을 제어하지 않으므로 의존하지 마십시오.

UUID와 유사한 것을 만들 수 있으며 수동으로 수행하면 고유성을 더 잘 보장 할 수 있습니다.

서로 다른 "유형"의 객체를 같은 컬렉션에 넣을 수 있으므로 두 "테이블"을 같은 컬렉션에 넣는 것은 어떻습니까? 동일한 _id 공간을 공유하므로 고유하게 보장됩니다. "예비"에서 "등록"으로 전환하면 필드를 간단히 뒤집을 수 있습니다.


1
_id 필드를 일반적으로 ObjectID 유형과 혼동하고 있다고 생각합니다. ObjectID 유형은 UUID처럼 취급 될 수 있도록 고유하게 설계되었습니다. 그러나 _id 필드는 모든 유형이 될 수 있으며 예제의 문자열과 같이 키에 다른 유형을 사용하는 경우 단일 컬렉션에서만 고유성을 보장합니다.
mstearn

@mstearn (Nitpick) UUID가 고유 하다는 개념 에는 결함이 있습니다. 좋은 UUID / 시퀀스 생성 전략은 충돌을 거의 일으키지 않지만 생성기 간의 절대 고유성 을 보장 하기 위해 고유 생성기 (예 : 고유 위치)를 고려해야합니다 . 물론 대부분의 확률은 너무 낮아 적용 가능한 우려가 없습니다 :-) GUID . 한 가지 문제 않습니다 하지만 올 대신 새로운 세대의 ID를 복사 / 복제입니다.

1
@pst : MongoDBs ObjectID에는 생성 프로세스의 pid와 호스트 이름의 해시에 기반한 일부 바이트가 모두 포함됩니다. 타임 스탬프 및 증분 카운터와 결합하면 별도로 생성 된 두 개의 ObjectID가 전체적으로 / 일반적으로 고유 할 가능성이 매우 높습니다. 물론 당신이 말한 것처럼 새로 생성 된 ObjectID에만 적용됩니다.
mstearn

1
ObjectId 유형을 참조하고 있습니다. '_id'에 문자열 값을 지정하지 않았습니다. 물론 동일한 문자열로 수동 설정하면 충돌이 동일합니다.
Anthony Jack

예, 게시물에 내용이 명확 해졌습니다. _id는 확실히 고유하지 않으며 ObjectId 생성 기능을 제어하지 않기 때문에 _id를 사용하는 것은 좋지 않습니다.
slacy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.