Ist es möglich, dass dieselbe exakte Mongo ObjectId für ein Dokument in zwei verschiedenen Sammlungen generiert wird? Mir ist klar, dass es definitiv sehr unwahrscheinlich ist, aber ist es möglich?
Der Grund, den ich frage, ist, dass wir mit einer Anwendung, an der ich arbeite, öffentliche Profile von gewählten Beamten anzeigen, die wir hoffentlich in vollwertige Benutzer unserer Website umwandeln können. Wir haben separate Sammlungen für Benutzer und gewählte Beamte, die derzeit keine Mitglieder unserer Website sind. Es gibt verschiedene andere Dokumente, die verschiedene Daten über die gewählten Beamten enthalten, die alle der Person mit ihrer gewählten offiziellen Objekt-ID zugeordnet sind.
Nach dem Erstellen des Kontos markieren wir weiterhin die Daten, die dem gewählten Beamten zugeordnet sind, aber sie sind jetzt auch Teil der Benutzersammlung mit einer entsprechenden Benutzer-ObjectId, um ihr Profil Interaktionen mit unserer Anwendung zuzuordnen.
Wir haben vor einigen Monaten damit begonnen, unsere Anwendung von MySql auf Mongo zu konvertieren. Während des Übergangs speichern wir die alte MySql-ID für beide Datentypen und beginnen nun auch damit, die gewählte offizielle Mongo ObjectId in den Benutzern zu speichern Dokument, um es wieder den gewählten offiziellen Daten zuzuordnen.
Ich habe darüber nachgedacht, nur die neue Benutzer-Objekt-ID als die zuvor gewählte offizielle Objekt-ID anzugeben, um die Dinge zu vereinfachen, wollte aber sicherstellen, dass es nicht möglich ist, eine Kollision mit einer vorhandenen Benutzer-Objekt-ID zu haben.
Vielen Dank für Ihren Einblick.
Bearbeiten: Kurz nachdem ich diese Frage gestellt hatte, stellte ich fest, dass meine vorgeschlagene Lösung keine sehr gute Idee war. Es wäre besser, nur das aktuelle Schema beizubehalten und nur auf die gewählte offizielle '_id' im Benutzerdokument zu verlinken.
Antworten:
Kurze Antwort
Nur um eine direkte Antwort auf Ihre erste Frage hinzuzufügen: JA, wenn Sie die BSON-Objekt-ID-Generierung verwenden, werden die IDs für die meisten Treiber mit ziemlicher Sicherheit in allen Sammlungen eindeutig sein. Weiter unten erfahren Sie, was "mit ziemlicher Sicherheit" bedeutet.
Lange Antwort
Die von Mongo DB-Treibern generierten BSON-Objekt-IDs sind höchstwahrscheinlich in allen Sammlungen eindeutig. Dies liegt hauptsächlich an den letzten 3 Bytes der ID, die für die meisten Treiber über einen statischen Inkrementierungszähler generiert werden. Dieser Zähler ist sammlungsunabhängig; es ist global. Der Java-Treiber verwendet beispielsweise eine zufällig initialisierte statische AtomicInteger.
Warum sagen sie in den Mongo-Dokumenten, dass die IDs "höchstwahrscheinlich" eindeutig sind, anstatt direkt zu sagen, dass sie eindeutig sein werden? Es gibt drei Möglichkeiten, bei denen Sie keine eindeutige ID erhalten (lassen Sie mich wissen, wenn weitere vorhanden sind):
Denken Sie vor dieser Diskussion daran, dass die BSON-Objekt-ID besteht aus:
[4 Bytes Sekunden seit der Epoche, 3 Bytes Maschinen-Hash, 2 Bytes Prozess-ID, 3 Bytes Zähler]
Hier sind die drei Möglichkeiten, damit Sie selbst beurteilen können, wie wahrscheinlich es ist, dass Sie betrogen werden:
1) Zählerüberlauf: Der Zähler enthält 3 Bytes. Wenn Sie zufällig in einer Sekunde mehr als 16.777.216 (2 ^ 24) Dokumente auf demselben Computer im selben Prozess einfügen, können Sie die inkrementierenden Zählerbytes überlaufen und am Ende zwei Objekt-IDs erhalten, die dieselbe Zeit haben, Computer , Prozess- und Zählerwerte.
2) Zähler nicht inkrementierend: Einige Mongo-Treiber verwenden Zufallszahlen anstelle von inkrementierenden Zahlen für die Zählerbytes. In diesen Fällen besteht eine 1 / 16,777,216-Chance, eine nicht eindeutige ID zu generieren, jedoch nur, wenn diese beiden IDs in derselben Sekunde (dh bevor der Zeitabschnitt der ID auf die nächste Sekunde aktualisiert wird) auf derselben generiert werden Maschine, im gleichen Prozess.
3) Maschinen- und Prozess-Hash auf die gleichen Werte. Die Werte für Maschinen-ID und Prozess-ID können in einem höchst unwahrscheinlichen Szenario denselben Werten für zwei verschiedene Maschinen zugeordnet werden. Wenn dies auftritt und gleichzeitig die beiden Zähler auf den beiden verschiedenen Computern in derselben Sekunde denselben Wert generieren, erhalten Sie eine doppelte ID.
Dies sind die drei Szenarien, auf die Sie achten müssen. Szenario 1 und 3 scheinen höchst unwahrscheinlich, und Szenario 2 ist völlig vermeidbar, wenn Sie den richtigen Treiber verwenden. Sie müssen die Quelle des Treibers überprüfen, um sicher zu sein.
quelle
ObjectId
Sie zuvor hatten, solange der Maschinen-Hash, die Prozess-ID und der Zähler alle gleichObjectIds werden clientseitig auf ähnliche Weise wie UUID generiert, jedoch mit einigen besseren Eigenschaften für die Speicherung in einer Datenbank, z. B. der ungefähren Erhöhung der Reihenfolge und der kostenlosen Codierung ihrer Erstellungszeit. Der Schlüssel für Ihren Anwendungsfall ist, dass sie so konzipiert sind, dass sie die Eindeutigkeit mit hoher Wahrscheinlichkeit garantieren, selbst wenn sie auf verschiedenen Maschinen generiert werden.
Wenn Sie sich nun allgemein auf das Feld _id beziehen, benötigen wir keine Eindeutigkeit für alle Sammlungen, sodass die alte _id sicher wiederverwendet werden kann. Wenn Sie beispielsweise zwei Sammlungen haben
colors
undfruits
beide gleichzeitig ein Objekt wie haben könnten{_id: 'orange'}
.Wenn Sie mehr darüber erfahren möchten, wie ObjectIds erstellt werden, finden Sie hier die Spezifikation: http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-BSONObjectIDSpecification
quelle
Falls jemand Probleme mit doppelten Mongo-Objekt-IDs hat, sollten Sie wissen, dass es trotz der Unwahrscheinlichkeit von Dups in Mongo selbst möglich ist, doppelte _ids mit PHP in Mongo zu generieren.
Der Anwendungsfall, in dem dies für mich regelmäßig passiert ist, ist, wenn ich einen Datensatz durchlaufe und versuche, die Daten in eine Sammlung einzufügen.
Das Array, das die Injektionsdaten enthält, muss bei jeder Iteration explizit zurückgesetzt werden - auch wenn Sie den Wert _id nicht angeben. Aus irgendeinem Grund fügt der INSERT-Prozess dem Array die Mongo _id hinzu, als wäre es eine globale Variable (auch wenn das Array keinen globalen Bereich hat). Dies kann sich auch dann auf Sie auswirken, wenn Sie die Einfügung in einem separaten Funktionsaufruf aufrufen, bei dem normalerweise zu erwarten ist, dass die Werte des Arrays nicht auf die aufrufende Funktion zurückgesetzt werden.
Hierfür gibt es drei Lösungen:
unset()
das Feld _id aus dem Array entfernenarray()
jedem Durchlaufen Ihres Datasets neu initialisierenIch vermute, dass dies ein Fehler in der PHP-Oberfläche ist und nicht so sehr ein Problem mit Mongo, aber wenn Sie auf dieses Problem stoßen, deaktivieren Sie einfach die _id und es sollte Ihnen gut gehen.
quelle
Es gibt keinerlei Garantie für die Eindeutigkeit von ObjectId in verschiedenen Sammlungen. Selbst wenn es wahrscheinlich sehr unwahrscheinlich ist, wäre es ein sehr schlechtes Anwendungsdesign, das sich auf die Einzigartigkeit von _id in allen Sammlungen stützt.
Man kann dies leicht in der Mongo-Schale testen:
Verlassen Sie sich also absolut nicht darauf, dass _id in allen Sammlungen eindeutig ist, und verlassen Sie sich nicht darauf, da Sie die ObjectId-Generierungsfunktion nicht steuern.
Es ist möglich, etwas zu erstellen, das eher einer UUID ähnelt. Wenn Sie dies manuell tun, können Sie die Einzigartigkeit besser garantieren.
Denken Sie daran, dass Sie Objekte unterschiedlicher "Typen" in dieselbe Sammlung aufnehmen können. Warum also nicht einfach Ihre beiden "Tabellen" in dieselbe Sammlung einfügen? Sie würden sich den gleichen ID-Raum teilen und somit garantiert einzigartig sein. Der Wechsel von "Interessent" zu "Registriert" wäre ein einfaches Umblättern eines Feldes ...
quelle