これを解決するには、少なくとも2つの適切な方法があります。実際には、もう1つはハックの問題ですが、正しく動作します。私はgist with a complete example (tested)を作成しました。
クライアント
BSONObjectId
にBSONObjectId
を生成することで、簡単にユニークな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 identifier
とthread 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が必要な場合もありますので、検討する価値があります。
あなたは 'insertResult.map(_。result [Person])'やあなたが使っているもの、 'BSONDocument'を使ってIDを取得することができます。ここのドキュメントにあります:http://reactivemongo.org/releases/0.11/documentation/tutorial/write-documents.html –
これは設計上の問題です。 IDを生成するためにDBがこのような問題につながることを期待する。 'BSONObjectID.generate'(または他のUUIDジェネレータ)を使うのがよいでしょう。 – cchantep