1. ホーム
  2. mongodb

[解決済み】2つの異なるコレクションで重複したMongo ObjectIdが生成される可能性?

2022-04-11 08:12:44

質問

2つの異なるコレクションにあるドキュメントに対して、まったく同じ Mongo ObjectId を生成することは可能でしょうか? 可能性は低いと思いますが、可能なのでしょうか?

あまり具体的なことは言えませんが、私が取り組んでいるアプリケーションで、私たちのサイトの本格的なユーザーに変換することを望んでいる選出された公務員の公開プロフィールを表示している理由です。 ユーザーと、現在サイトのメンバーでない当選者のコレクションを分けています。 その他にも、当選者についてのさまざまなデータを含むドキュメントがあり、それらはすべて当選者の ObjectId を使用して本人にマップバックされています。

アカウントを作成した後も、選出された職員に関連するデータを強調表示しますが、対応するユーザー ObjectId を持つユーザーコレクションの一部にもなり、アプリケーションとのインタラクションにプロファイルをマッピングします。

数ヶ月前にアプリケーションを MySql から Mongo に変換し始めましたが、移行中はこれら両方のデータ型に対して従来の MySql ID を保存し、さらに選出された役人のデータに対応するために、users ドキュメントに選出された役人の Mongo ObjectId を保存し始めました。

新しいユーザーObjectIdを以前の当選者ObjectIdとして指定することでシンプルにしようと考えていましたが、既存のユーザーObjectIdと衝突する可能性がないことを確認したいと思いました。

ご教示ありがとうございました。

編集:この質問を投稿した直後、私が提案した解決策はあまり良いアイデアではないことに気づきました。 現在のスキーマを維持したまま、ユーザードキュメントの当選者'_id'にリンクするだけにしたほうがよさそうです。

解決方法は?

簡単な答え

最初の質問に対する直接の回答を補足します。はい、もしあなたがBSONオブジェクトIDの生成を使用するのであれば ほとんどのドライバで IDはコレクション間でほぼ確実に一意となります。ほぼ間違いないとはどういう意味か、以下を参照してください。

長い回答

Mongo DBのドライバが生成するBSONオブジェクトIDは、コレクション間でユニークである可能性が高いです。これは主に ID の最後の 3 バイトのせいです。 ほとんどのドライバで は、静的なインクリメントカウンターによって生成されます。このカウンターはコレクションに依存せず、グローバルなものです。例えば、Javaドライバでは、ランダムに初期化される静的なAtomicIntegerを使用します。

ではなぜ Mongo のドキュメントでは、ID は必ず一意になるとは言わず、一意になる可能性が高い ("highly likely") と言っているのでしょう? 一意な ID が得られない場合、3 つの可能性が考えられます (他にもあったら教えてください)。

この議論の前に、BSONオブジェクトIDは、以下のような構成になっていることを思い出してください。

[4バイトのエポックからの秒数、3バイトのマシンハッシュ、2バイトのプロセスID、3バイトのカウンタ]。

以下、3つの可能性を示しますので、どの程度の確率でダブリが発生するかをご自身でご判断ください。

1) カウンタのオーバーフロー:カウンタには3バイトがあります。同じマシン、同じプロセスで、1秒間に 16,777,216 (2^24) 個以上のドキュメントを挿入すると、増加するカウンタバイトがオーバーフローして、同じ時間、マシン、プロセス、カウンタ値を共有する 2 つのオブジェクト ID になってしまう可能性があるのです。

2) カウンターがインクリメントしない: いくつかの Mongo ドライバはカウンターバイトにインクリメントする数字ではなく、乱数を使います。この場合、1/16,777,216 の確率で一意でない ID が生成されます。ただし、2 つの ID が同じ秒数 (つまり ID の時間セクションが次の秒に更新される前) に、同じマシン、同じプロセスで生成された場合のみです。

3) マシンとプロセスのハッシュ値が同じである。マシンIDとプロセスIDの値は、ある非常に可能性の低いシナリオでは、2つの異なるマシンに対して同じ値にマッピングされるかもしれません。この場合、2つの異なるマシン上の2つのカウンタが、同じ秒数で同じ値を生成すると、IDが重複してしまうことになります。

以上、3つのシナリオに注意してください。シナリオ1と3は可能性が低いと思われ、シナリオ2は正しいドライバを使用していれば完全に回避できます。ドライバーのソースを確認する必要があります。