2016-03-23 19 views
3

私はこの質問が早く(ほぼ3年前に)尋ねられたようだが、それ以来、反応型mongoライブラリには多くの変更があるかもしれないことが分かった。reactmongoに挿入した後でドキュメントオブジェクトIDを取得する方法は?

私はバージョン2.4でplayプラグインを使用していますが、reactmongo.api.commands.WriteResultにはドキュメントオブジェクトIDを取得するAPIがないようです。

私はオブジェクトIDを自分で設定することができますが、IDを作成するマシン上でユニークな値が他のマシンと同じでない可能性があり、物事を維持するために説得力のある正しいアイデアは見つけられませんシンプルな私はこれをmongo dbによって処理させたいと思っています。

私は挿入された文書のIDを得ることができる場合は大丈夫ですか、そうでなければ、私は避けるためにしようとしている自分自身でIDを設定する方法にフォールバックする必要があります。

+0

あなたは 'insertResult.map(_。result [Person])'やあなたが使っているもの、 'BSONDocument'を使ってIDを取得することができます。ここのドキュメントにあります:http://reactivemongo.org/releases/0.11/documentation/tutorial/write-documents.html –

+0

これは設計上の問題です。 IDを生成するためにDBがこのような問題につながることを期待する。 'BSONObjectID.generate'(または他のUUIDジェネレータ)を使うのがよいでしょう。 – cchantep

答えて

1

ObjectIdをクライアント側で作成するのは問題ありません。​​(MongoDB用MongoDBのブロックドライバ)は、コードを掘り下げれば何をしているのですか?

ObjectIdフィールドを見ると、a 3-byte machine identifierが表示されます。それは(標準のJavaドライバではInetAddressを含む)やりにくく計算されます。異なるマシン上に同時に生成される2 ObjectIdの間に衝突が発生しないことを保証します。

4

これを解決するには、少なくとも2つの適切な方法があります。実際には、もう1つはハックの問題ですが、正しく動作します。私はgist with a complete example (tested)を作成しました。

クライアント

BSONObjectIdBSONObjectIdを生成することで、簡単にユニークなIDを生成するために使用することができますgenerateと呼ばれる方法があります。得られたIDは、MongoDBのサーバ自体によって生成されたIDと同一の構造を有する:

+------------------------+------------------------+------------------------+------------------------+ 
+ timestamp (in seconds) + machine identifier + thread identifier +  increment  + 
+  (4 bytes)  +  (3 bytes)  +  (2 bytes)  +  (3 bytes)  + 
+------------------------+------------------------+------------------------+------------------------+ 

BSONObjectId.generateためReactiveMongo者のJavadocから採取)

例コード:

val id = BSONObjectId.generate() 
collection.insert(BSONDocument("_id" -> id, "foo" -> "bar")) 

得られたIDではないであろうサーバーによって生成されたのとまったく同じです。具体的には、machine identifierthread identifierは完全に異なる可能性があります。しかし、ほとんどの(すべての)ケースでは、衝突のリスクは無視できるので、問題ではないので、私の意見ではこれが最良のアプローチです。

insertによって返される値もチェックする必要があります。失敗した場合は、新しいIDを生成して、再度挿入することができます。このようにして、あなたのコードは防弾でなければなりません。再試行回数を制限し、各試行の間にランダムな遅延を追加することを忘れないでください。使用BSONCollection.findAndUpdate

あなたが実際にいくつかのあいまいな理由で、サーバー側のIDを生成する必要がある場合

は、このソリューションは、競合状態、または任意の追加のクエリを避け、それを行う必要がありますので、多少ハックとはいえ、非常に最適です。そのトリックは、MongoDBのfindAndModifyを使うことです。この方法では、WriteResultの代わりにFindAndModifyResultが表示され、挿入されたドキュメントにアクセスできます。例:

val resultFuture = collection.findAndUpdate(
    selector  = BSONDocument("foo" -> -1), // Assuming that there's no document with "foo" equal to -1, otherwise THIS CODE MAY EXPLODE 
    update   = BSONDocument("foo" -> "bar"), 
    fetchNewObject = true, 
    upsert   = true) 
val idFuture: Future[BSONObjectId] = resultFuture.map { result => 
    val doc = result.value.get // WARNING: I'm using get for simplicity, but you shouldn't: it may throw an exception 
    doc.getAs[BSONObjectId]("_id")) 
} 

そうでない場合、これは代わりに新しいものを挿入する既存のドキュメントを更新してしまう、あなたが文書を選択したことがないselectorを提供しなければならないことに注意してください。さらに、updateのこれらのフィールドをオーバーライドする必要があります。そうでない場合はselectorの値が使用されます。

ボーナス:またMongoDB's documentationで説明したように、最新のIDを維持するための追加的なコレクションを作成することができ、増分のID

のための分別収集を使用してください。新しいIDを取得して値を増やすには、findAndModifyを使用している限り、これは安全です。欠点? 1つの追加のコレクションと1つの追加のクエリがありますが、自動インクリメントされた一意のIDが必要な場合もありますので、検討する価値があります。

+0

こんにちは、これは私の最初の投稿StackOverflowです。私が何か良いことをしたと思うかどうかを教えてください。 –

+0

findAndUpdateの興味深い使い方、不一致のセレクタを提供する必要があることは残念ですが、私はおそらくプロダクションアプリでこのアプローチを使用することをお勧めしません。 – qwwqwwq

+0

はい、**私は決して使っていません。それでもなお良いオブジェクトを挿入し、最も高いID(競合状態)をDBに照会します。誰かが知っている、おそらく誰かがIDのサーバー側を生成するための正当な理由があるので、私はこの解決策を保つでしょう。 –

関連する問題