web-dev-qa-db-ja.com

重複するMongo ObjectIdが2つの異なるコレクションで生成される可能性はありますか?

2つの異なるコレクション内のドキュメントに対して、まったく同じMongo ObjectIdを生成できますか?私はそれが間違いなく非常にありそうもないことを理解していますが、それは可能ですか?

具体的になりすぎないで、私が尋ねる理由は、私が取り組んでいるアプリケーションで、当サイトの本格的なユーザーに転換したい選出された役人の公開プロフィールを表示するからです。ユーザーと、現在当サイトのメンバーではない選出された役員のために、別々のコレクションを用意しています。選出された役人に関するさまざまなデータを含むさまざまなドキュメントがあり、それらはすべて、選出された役人のObjectIdを使用する人物にマップされます。

アカウントを作成した後も、選出された役人に関連付けられているデータを強調表示しますが、それらは対応するユーザーObjectIdを持つユーザーコレクションの一部であり、プロファイルをアプリケーションとの対話にマップします。

数か月前にアプリケーションをMySqlからMongoに変換し始め、移行中にこれらの両方のデータ型のレガシーMySql idを保存し、ユーザーに選択された公式Mongo ObjectIdを保存し始めました選出された公式データにマップするドキュメント。

以前の選出された公式ObjectIdとして新しいユーザーObjectIdを指定するだけで物事を簡単にすることを考えていましたが、既存のユーザーObjectIdと衝突しないようにしたかったのです。

洞察力をありがとう。

編集:この質問を投稿してまもなく、提案された解決策はあまり良いアイデアではないことに気付きました。現在のスキーマをそのまま保持し、ユーザー文書で選出された公式の「_id」にリンクすることをお勧めします。

164
Anthony Jack

短い答え

最初の質問に直接回答を追加するために:はい、BSONオブジェクトID生成を使用する場合、ほとんどのドライバーでIDはコレクション間でほぼ確実に一意になります。 「ほぼ確実に」の意味については、以下を参照してください。

ロングアンサー

Mongo DBドライバーによって生成されたBSONオブジェクトIDは、コレクション全体で一意である可能性が高いです。これは主に、IDの最後の3バイトが原因であり、ほとんどのドライバでは静的な増分カウンタを介して生成されます。そのカウンターはコレクションに依存しません。グローバルです。たとえば、Javaドライバーは、ランダムに初期化された静的AtomicIntegerを使用します。

それでは、なぜ、Mongoのドキュメントでは、彼らはIDが一意であるとはっきり言っているのではなく、IDが一意である可能性が高いと言っているのでしょうか。一意のIDを取得できない場合は、次の3つの可能性があります(さらにIDがある場合はお知らせください)。

この議論の前に、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は完全に回避できます。確実に知るために、ドライバーのソースを確認する必要があります。

293
Raj Advani

ObjectIdは、UUIDに似た方法でクライアント側で生成されますが、順序を大まかに上げたり、作成時間を無料でエンコードしたりするなど、データベースに保存するための優れたプロパティがあります。ユースケースの重要な点は、異なるマシンで生成された場合でも、高い確率で一意性を保証するように設計されていることです。

一般的に_idフィールドを参照している場合、コレクション全体で一意である必要はないため、古い_idを再利用しても安全です。具体例として、colorsfruitsの2つのコレクションがある場合、両方が同時に{_id: 'orange'}のようなオブジェクトを持つことができます。

ObjectIdの作成方法について詳しく知りたい場合は、仕様を以下に示します。 http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-BSONObjectIDSpecification

13
mstearn

重複するMongo ObjectIDで問題が発生した場合、Mongo自体で発生する可能性の低い重複にもかかわらず、MongoのPHPで_idが重複して生成される可能性があることを知っておく必要があります。

私にとってこれが規則的に起こったユースケースは、データセットをループしてコレクションにデータを注入しようとするときです。

_id値を指定していない場合でも、注入データを保持する配列は各反復で明示的にリセットする必要があります。何らかの理由で、INSERTプロセスは、Mongo _idをグローバル変数であるかのように配列に追加します(配列にグローバルスコープがない場合でも)。これは、通常、配列の値が呼び出し元の関数に保持されないことが予想される別の関数呼び出しで挿入を呼び出している場合でも、影響する可能性があります。

これには3つの解決策があります。

  1. unset()配列の_idフィールドを使用できます
  2. データセットをループするたびに、array()を使用して配列全体を再初期化できます
  3. _idの値は自分で明示的に定義できます(重複を生成しないように定義するよう注意してください)。

私の推測では、これはPHPインターフェースのバグであり、Mongoの問題ではありませんが、この問題に遭遇した場合は、_idの設定を解除するだけで問題ありません。

11
DenverMatt