Es gibt mindestens zwei Möglichkeiten, dies zu lösen. Eigentlich ist der zweite eher ein Hack, aber er funktioniert richtig. Ich habe ein gist with a complete example (tested) erstellt.
generieren BSONObjectId
auf dem Client
BSONObjectId
hat eine Methode namens generate
, die Sie leicht eine eindeutige ID generieren verwenden können. Die sich ergebende ID die gleiche Struktur wie IDs, die durch MongoDB Server hat sich:
+------------------------+------------------------+------------------------+------------------------+
+ timestamp (in seconds) + machine identifier + thread identifier + increment +
+ (4 bytes) + (3 bytes) + (2 bytes) + (3 bytes) +
+------------------------+------------------------+------------------------+------------------------+
(für BSONObjectId.generate
von ReactiveMongo des Javadoc- genommen)
Beispielcode:
val id = BSONObjectId.generate()
collection.insert(BSONDocument("_id" -> id, "foo" -> "bar"))
die resultierende ID wird nicht genau wie vom Server generiert werden. Insbesondere machine identifier
und thread identifier
wird höchstwahrscheinlich völlig anders sein. In den meisten (allen?) Fällen spielt es jedoch keine Rolle, denn das Risiko einer Kollision ist vernachlässigbar, daher ist dies meines Erachtens der beste Ansatz.
Sie sollten auch den von insert
zurückgegebenen Wert überprüfen. Wenn dies fehlschlägt, können Sie eine neue ID generieren und erneut versuchen, einzufügen. Auf diese Weise sollte Ihr Code kugelsicher sein. Denken Sie daran, die Anzahl der Wiederholungen zu begrenzen und vielleicht zwischen jedem Versuch eine zufällige Verzögerung hinzuzufügen.
Verwenden BSONCollection.findAndUpdate
Wenn Sie wirklich brauchen, um IDs auf der Serverseite aus unerfindlichen Gründen zu erzeugen, sollte diese Lösung das tut, Rennen oder zusätzliche Abfragen zu vermeiden, so ist es ganz optimal, wenngleich etwas hacky. Der Trick besteht darin, MongoDB findAndModify
zu verwenden. Auf diese Weise erhalten Sie FindAndModifyResult
anstelle von WriteResult
, mit dem Sie auf das eingefügte Dokument zugreifen können.Beispiel:
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"))
}
Bitte beachten Sie, dass Sie ein selector
bereitstellen muss, die nie ein Dokument auswählt, sonst wäre dies ein vorhandenes Dokument aktualisieren, anstatt einen neuen einzufügen. Außerdem müssen Sie diese Felder in update
überschreiben, andernfalls würden Sie die Werte von selector
verwenden.
Bonus: eine getrennte Sammlung für inkrementelle IDs verwenden
Sie können auch eine zusätzliche Sammlung schaffen für die Führung der jüngsten ID wie in MongoDB's documentation beschrieben. Dies sollte sicher sein, solange Sie findAndModify
verwenden, um gleichzeitig eine neue ID zu erhalten und den Wert zu erhöhen. Nachteile? Eine zusätzliche Sammlung und eine zusätzliche Abfrage, aber es gibt einige Fälle, in denen Sie ohnehin automatisch inkrementierte eindeutige IDs benötigen. Daher ist es möglicherweise eine Überlegung wert.
Sie können 'insertResult.map (_. Ergebnis [Person])' oder was auch immer Sie verwenden, auch 'BSONDocument' und holen Sie sich die ID aus. Gefunden in der Dokumentation hier: http://reactivemongo.org/releases/0.11/documentation/tutorial/write-documents.html –
Das ist ein Design-Problem. Zu erwarten, dass die DB eine ID generiert, führt zu einem solchen Problem. Es ist besser, 'BSONObjectID.generate' (oder einen anderen UUID-Generator) zu verwenden. – cchantep