web-dev-qa-db-fra.com

Possibilité que des objets Mongo en double soient générés dans deux collections différentes?

Est-il possible que le même ObjectId Mongo soit généré pour un document appartenant à deux collections différentes? Je réalise que c'est vraiment très improbable, mais est-ce possible?

Sans entrer dans les détails, la raison pour laquelle je pose cette question est qu'avec une application sur laquelle je travaille, nous montrons les profils publics d'élus que nous espérons convertir en utilisateurs à part entière de notre site. Nous avons des collections séparées pour les utilisateurs et les élus qui ne sont pas actuellement membres de notre site. Il existe divers autres documents contenant diverses données sur les élus qui sont tous reliés à la personne qui utilise leur ObjectId officiel élu.

Après avoir créé le compte, nous mettons toujours en surbrillance les données associées à l'élu élu, mais elles font maintenant partie de la collection d'utilisateurs avec un ObjectId d'utilisateur correspondant pour mapper leur profil aux interactions avec notre application.

Nous avions commencé la conversion de notre application MySQL en Mongo il y a quelques mois et pendant que nous sommes en transition, nous stockons l'ancien identifiant MySql pour ces deux types de données. document à mettre en correspondance avec les données officielles élues.

Je réfléchissais juste à spécifier le nouvel utilisateur ObjectId en tant que ObjectId officiel élu précédent pour simplifier les choses, mais je voulais m'assurer qu'il ne serait pas possible d'avoir une collision avec un utilisateur ObjectId existant.

Merci pour votre perspicacité.

Edit: Peu de temps après avoir posté cette question, je me suis rendu compte que ma solution proposée n’était pas une très bonne idée. Il serait préférable de simplement conserver le schéma actuel et de créer un lien avec le représentant élu "_id" dans le document des utilisateurs.

164
Anthony Jack

Réponse courte

Juste pour ajouter une réponse directe à votre question initiale: OUI, si vous utilisez la génération d’ID objet BSON, alors pour la plupart des pilotes , les identifiants vont presque certainement être unique dans toutes les collections. Voir ci-dessous ce que "presque certainement" signifie.

Réponse longue

Les identifiants d'objet BSON générés par les pilotes de base de données Mongo sont très probablement uniques parmi les collections. Cela est principalement dû aux 3 derniers octets de l'ID, qui pour la plupart des pilotes est généré via un compteur d'incrémentation statique. Ce compteur est indépendant de la collection; c'est global. Le pilote Java, par exemple, utilise un AtomicInteger statique initialisé de manière aléatoire.

Alors pourquoi, dans les documents Mongo, dit-on que les identifiants sont "très probablement" uniques, au lieu de dire carrément qu'ils SERONT uniques? Trois possibilités peuvent se présenter sans identifiant unique (merci de me faire savoir s'il en existe d'autres):

Avant cette discussion, rappelez-vous que l’objet BSON comprend:

[4 octets de secondes depuis l'époque, 3 octets de hachage de la machine, identificateur de processus de 2 octets, compteur de 3 octets]

Voici les trois possibilités, donc vous jugerez vous-même de la probabilité d’obtenir une dupe:

1) Dépassement de compteur: il y a 3 octets dans le compteur. S'il vous arrive d'insérer plus de 16 777 216 (2 ^ 24) documents en une seconde, sur le même ordinateur et dans le même processus, vous pouvez alors surcharger les octets du compteur d'incrémentation et vous retrouver avec deux ID d'objet partageant le même temps, ordinateur , processus et valeurs de compteur.

2) Compteur non incrémenté: certains pilotes Mongo utilisent des nombres aléatoires au lieu d’incrémenter les octets du compteur. Dans ces cas, il y a 1 chance sur 16 777 216 de générer un identifiant non unique, mais uniquement si ces deux identifiants sont générés dans la même seconde (c.-à-d. Avant que la section de l'heure de l'ID ne se mette à la seconde suivante), sur la même machine, dans le même processus.

3) Machine et processus de hachage aux mêmes valeurs. Les valeurs d'ID d'ordinateur et d'ID de processus peuvent, dans certains cas hautement improbables, correspondre aux mêmes valeurs pour deux machines différentes. Si cela se produit et que les deux compteurs situés sur les deux ordinateurs différents génèrent la même valeur en même temps, vous obtiendrez un ID en double.

Ce sont les trois scénarios à surveiller. Les scénarios 1 et 3 semblent très improbables, et le scénario 2 est totalement évitable si vous utilisez le bon pilote. Vous devrez vérifier la source du pilote pour savoir à coup sûr.

293
Raj Advani

Les ObjectIds sont générés côté client d'une manière similaire à UUID, mais avec certaines propriétés plus agréables pour le stockage dans une base de données, telles que l'ordre croissant et l'ordre de leur temps de création gratuitement. L'essentiel pour votre cas d'utilisation est qu'ils sont conçus pour garantir l'unicité des chances, même s'ils sont générés sur des machines différentes.

Maintenant, si vous vous référiez au champ _id en général, nous n’exigeons pas que les collections soient uniques, il est donc prudent de réutiliser l’ancien _id. Comme exemple concret, si vous avez deux collections, colors et fruits, les deux peuvent simultanément avoir un objet comme {_id: 'orange'}.

Si vous souhaitez en savoir plus sur la manière dont les ObjectIds sont créés, voici la spécification: http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-BSONObjectIDSpecification

13
mstearn

Au cas où quelqu'un aurait des problèmes avec les identifiants Mongo ObjectID, vous devez savoir que, malgré le risque infaillible que des erreurs se produisent dans Mongo lui-même, il est possible d'avoir des ids en double générés avec PHP dans Mongo.

Le cas d'utilisation où cela s'est produit avec régularité pour moi est lorsque je parcours en boucle un jeu de données et tente d'injecter les données dans une collection.

Le tableau contenant les données d'injection doit être explicitement réinitialisé à chaque itération, même si vous ne spécifiez pas la valeur _id. Pour une raison quelconque, le processus INSERT ajoute le Mongo _id au tableau comme s'il s'agissait d'une variable globale (même si le tableau n'a pas de portée globale). Cela peut vous affecter même si vous appelez l'insertion dans un appel de fonction séparé dans lequel vous vous attendez normalement à ce que les valeurs du tableau ne persistent pas jusqu'à la fonction appelante.

Il y a trois solutions à cela:

  1. Vous pouvez unset() le champ _id du tableau
  2. Vous pouvez réinitialiser tout le tableau avec array() chaque fois que vous parcourez votre ensemble de données.
  3. Vous pouvez définir explicitement la valeur _id vous-même (en prenant soin de la définir de manière à ne pas générer de doublons).

À mon avis, il s’agit d’un bogue de l’interface PHP, ce n’est pas un problème avec Mongo, mais si vous rencontrez ce problème, désactivez simplement le _id et tout devrait bien se passer.

11
DenverMatt