これを解決するには、少なくとも 2 つの適切な方法があります。実際には、2 番目のものはよりハックですが、適切に動作します。完全な例 (テスト済み) を含む要旨を作成しました。
BSONObjectId
クライアント上で生成
BSONObjectId
generate
には、一意の ID を簡単に生成するために使用できるメソッドがあります。結果の ID は、MongoDB サーバー自体によって生成された ID と同じ構造になります。
+------------------------+------------------------+------------------------+------------------------+
+ timestamp (in seconds) + machine identifier + thread identifier + increment +
+ (4 bytes) + (3 bytes) + (2 bytes) + (3 bytes) +
+------------------------+------------------------+------------------------+------------------------+
(ReactiveMongo の javadoc for から取得BSONObjectId.generate
)
コード例:
val id = BSONObjectId.generate()
collection.insert(BSONDocument("_id" -> id, "foo" -> "bar"))
結果の ID は、サーバーによって生成されたものとまったく同じではありません。具体的には、machine identifier
まったくthread identifier
異なる可能性があります。ただし、衝突のリスクは無視できるため、ほとんどの場合 (すべて?) は問題になりません。私の意見では、これが最善の方法です。
によって返される値も確認する必要がありますinsert
。失敗した場合は、新しい ID を生成して、もう一度挿入してみてください。このようにして、コードは防弾になるはずです。再試行の回数を制限し、試行ごとにランダムな遅延を追加することを忘れないでください。
使用するBSONCollection.findAndUpdate
なんらかの理由でサーバー側で ID を生成する必要がある場合、このソリューションは競合状態や追加のクエリを回避して生成する必要があるため、ややハックではありますが、非常に最適です。秘訣は、MongoDB のfindAndModify
. このようにして、FindAndModifyResult
代わりに を取得WriteResult
し、挿入されたドキュメントにアクセスできます。例:
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
。
おまけ: 増分 ID には別のコレクションを使用する
MongoDB のドキュメントで説明されているように、最新の ID を保持するための追加のコレクションを作成することもできます。findAndModify
これは、新しい ID の取得と値のインクリメントを同時に行うために使用している限り、安全です。欠点?1 つの追加のコレクションと 1 つの追加のクエリですが、いずれにせよ自動インクリメントされた一意の ID が必要な場合があるため、検討する価値があるかもしれません。