2016-08-02 5 views
0

私はMongoDBコレクションに文書を連続的に挿入するアプリケーションを持っています。MongoDB - 挿入反映フィールド

私は、挿入命令の後にドキュメントを照会する方法を探しています。

私が使用していた候補者:

  • _idフィールド
  • 作成日付フィールド
  • シーケンス番号(自動インクリメント)

_idフィールドが良くありません候補者が言うように。作成日フィールドは良い候補であった可能性がありますが、クロックが同期していない可能性があるため、注文が破損する可能性があります。順序番号に関して、文書は2つのアプローチを提案します:カウンタと楽観的ループ。カウンターアプローチは、であっても、別の文書D2の後に文書D1が挿入される可能性があるため、挿入順序を保証しません。たとえば、D1がシーケンス番号5を占有し、次にD2がシーケンス番号6を捕捉した場合、D2が挿入され、次にD1が挿入されます。重い挿入環境の場合、楽観的なループアプローチは狂っています。

別の方法がありますか?


EDIT:

カウンタを使用したアプローチには問題があります。以下のシナリオを考えてみましょう。私は継続的に文書をコレクションに挿入するアプリケーションAを持っています。また、同じコレクションの文書を連続的にポーリングする別のアプリケーションBもあります。アプリケーションAはマルチスレッドです。 T1T2の2つのスレッドはそれぞれ文書D1D2を挿入しようとしています。挿入の途中で、アプリケーションBはさらに多くのドキュメントを要求します。操作の次の順序を想定します

  1. スレッドA-T1は、次のシーケンス番号N
  2. スレッドA-T2は、次のシーケンス番号N+1
  3. スレッドA-T2挿入D2
  4. アプリケーションBは(最後の仮定seq >= Nとの文書を要求押収押収処理された文書の番号はN-1)、D2D1
  5. スレッドに)まだA-T1挿入D1
  6. アプリケーションを挿入途中Bは、最後に処理された文書は、配列番号N+1)この場合

を持っているので、D1は処理されません(seq >= N+2との文書を要求します。

+0

私が正しく理解していれば、どのような順序で文書を作成し、保存したかを知る方法が必要です。自分で_idを生成することをお勧めします。たとえば、サーバーが起動すると、最後の_idが挿入されます(または最大のものが1505と同様)。その後、各文書のistert増加カウンターの上にだけ。そして、あなたは行くのが良いです。保存に失敗したドキュメントがあっても、それをいくつかのJSONファイルに保存して後で再保存することができます。 _idはその時までに生成され、あなたは注文システムを持っています。お役に立てれば。 –

+0

あなたのアプローチが質問の第3のアプローチとどのように違うかはわかりません。 –

+0

これはちょっとだけ言葉が同じです。 –

答えて

0

1秒あたり数十回の挿入が予想される場合は、楽観的ロックが唯一の方法です。

それ以外の場合は、クロック同期が良いアイデアかもしれません。

D1D2の後に保持されている場合、カウンターを考慮して、アプリケーションにどのような影響があるか詳しく説明できますか? mongodb自体の "挿入"操作には複数の段階があり、ジャーナリングに頼るのと同じくらい深くすることができます。

EDIT

あなたがアプリケーションBのオプションとしてtailable cursorを考えるだろうか?それは直接質問に答えませんが、それは問題の背後にある問題を解決するかもしれません。 2

EDITは、あなたはおそらく画像のように、アプリケーション間で通信するために、あらゆる種類のメッセージキューを使用する必要があります。それは過度の可能性がありますが、楽観的なロックがボトルネックであることが確かであれば、それは受け入れられるかもしれません。下の画像を

  1. アプリケーションAは、任意の順序に文書を挿入し、Mongoのクライアントからの固有のオブジェクトIDを取得します。

  2. 用途任意の順序でキューにOBJECTID A送信

  3. アプリケーションBがデータベース

からIDにより文書をフェッチB GET次のオブジェクトIDキューから

  • アプリケーション

    enter image description here

    EDIT 3

    最後に、あなたは文書にステータスを追加し、アプリケーションBに楽観的ロックをシフトするために検討することがあります。

    1. は、取得した未処理文書のオブジェクトID:db.collection.findOne({status: null}, {})

    2. ステータスを「処理中」に変更する

      db.collection.findAndModify({ 
          query: { _id: objectId, status: null }, 
          update: { $set: { status: 'processing' }} 
      }) 
      

      それがnullを返す場合 - 文書は文書1

    3. プロセスステップおよびそれが行わ 'にステータスのアップデートするBの別のインスタンスによって処理され、そう返している:

      db.collection.findAndModify({ 
          query: { _id: objectId, status: 'processing' }, 
          update: { $set: { status: 'done' }} 
      }) 
      

    この方法では、正確なシーケンスはまったく気にしません。ドキュメントを順番に処理したい場合は、ステップ1でタイムスタンプを追加したり、ObjectIdでリレーしてドキュメントをソートしたりできます。もちろん正確な順序ではないかもしれませんが、すべての文書が処理されることを保証する必要はありません。

  • +0

    私の編集 –

    +0

    あなたのコメントについて楽観的なループについては、私はそれが逆だと思う - 楽観的なループは、重複エラーなしで文書を挿入することができる前に複数の時間ループするので、 –

    +0

    ミリ秒単位でカウントすると、楽観的なロックとタイムスタンプの理由はNTPで十分ではないかもしれませんが、performnceについてのポイントを参照してください。あなたが**問題があることを証明するまで早すぎる最適化を避けるようにしてください。 あなたの編集に関して - アプリケーション 'B'はシーケンス番号をどうやって知っていますか?これはアプリケーションAドメインにのみ属します。 'B'は返品のみを求めることができます。シーケンス番号で順序付けられた最新の1000のドキュメント。 "timestampより古い"のような他のフィルタも、フィルタリングのためのタイムスタンプを追加すると仮定すると、大丈夫です。シーケンス番号はソートにのみ使用されます。 –

    関連する問題