3

1 億のドキュメントを含むコレクションがあります。多数のドキュメントを安全に更新したい (安全とは、ドキュメントがまだ更新されていない場合にのみドキュメントを更新することを意味します)。Mongoでそれを行う効率的な方法はありますか?

limit 句で $isolated 演算子を使用する予定でしたが、mongo は更新の制限をサポートしていないようです。

これは簡単に思えますが、私は立ち往生しています。どんな助けでも大歓迎です。

4

1 に答える 1

1

Sammaye によると、これを行うための「適切な」方法があるようには見えません。私の回避策は、mongo サイトで概説されているようにシーケンスを作成し、コレクション内のすべてのレコードに「seq」フィールドを追加することでした。これで、確実にソートして更新できる一意のフィールドができました。

ここでは、確実にソート可能であることが重要です。自動生成された _id でソートするつもりでしたが、自然な順序は ObjectId の昇順と同じではないことにすぐに気付きました (このページから、私が観察した動作と一致するオブジェクト値よりも文字列値が優先されるようです)テスト中)。また、レコードがディスク上で再配置される可能性も十分にあり、その結果、自然な順序がソートの信頼性を失います。

これで、包括的な開始点を取得するためにまだ更新されていない最小の「seq」を持つレコードを照会できるようになりました。次に、開始点よりも大きい「seq」を持つレコードをクエリし、更新したいレコードの数をスキップします (ドキュメントを削除すると「seq」がまばらになる可能性があるため、スキップすることが重要です...)。そのクエリに 1 の制限を設定すると、包括的でないエンドポイントが得られます。これで、'updated' = 0, 'seq' >= my starting point and < my endpoint のクエリで更新を発行できます。他のスレッドが私を打ち負かしていないと仮定すると、アップデートは私が望むものを与えるはずです.

手順は次のとおりです。

  1. findAndModify を使用して自動インクリメント シーケンスを作成する
  2. 自動インクリメント シーケンスを使用するコレクションにフィールドを追加します
  3. 適切な開始点を見つけるクエリ: db.xx.find({ updated: 0 }).sort({ seq: 1 }).limit(1)
  4. 適切なエンドポイントを見つけるクエリ: db.xx.find({ seq: { $gt: startSeq }}).sort({ seq: 1 }).skip(updateCount).limit(1)
  5. 開始点と終了点を使用してコレクションを更新します: db.xx.update({ updated: 0, seq: { $gte: startSeq }, seq: { $lt: endSeq }, $isolated: 1}, { updated: 1 } ,{ マルチ: true })

かなり痛いですが、それは仕事を成し遂げます。

于 2013-04-26T18:52:04.777 に答える