web-dev-qa-db-fra.com

Mongoose: les comparaisons ObjectId échouent de manière incohérente

J'ai un outil simple pour créer des collections de documents, puis les formater automatiquement pour un rendu EPUB ou LaTeX, écrit au-dessus d'ExpressJS. J'utilise Coffeescript, si cela compte (j'en doute).

En utilisant Mongoose, j'ai les éléments suivants:

DocumentSchema = new Schema
    title:     String

Offrefs = new Schema
    ref:       { type: ObjectId }
    isa:       String

BinderSchema = new Schema
    title:     String
    contains:  [Offrefs]

Offrefs ne précise pas ce à quoi elle fait référence car je veux pouvoir contenir des classeurs dans d'autres classeurs pour créer des collections logiques: "Celles-ci sont pour l'imprimante," "Celles-ci sont pour epub", "Ce sont uniquement des sites Web, "etc. (J'ai enlevé tous les trucs divers.)

Malheureusement, j'ai rencontré des requêtes où, pour les objets récupérés

(story._id == offref.ref) -> True 

Et les deux sont en effet identiques. Mais:

(binder._id == offref.ref) -> False
(String(binder._id) == String(offref.ref)) -> True

Et une comparaison visuelle des deux références dans les deux dernières, elles sont le même numéro d’identification, mais les objets ObjectId ne se comparent pas correctement.

Je ne veux pas avoir à faire constamment des conversions de chaînes, ce qui est une possibilité importante lorsque je convertis ces objets complexes en arbres de données. Les relations d'arborescence sont un ours dans n'importe quelle base de données; ils ne devraient pas être difficiles dans MongoDB.

Comment faites-vous des comparaisons ObjectId dans MongoDB?

28
Elf Sternberg

Une comparaison directe == (ou ===) comparera les deux objets par référence et non par valeur. Donc, cela ne sera évalué à vrai que s'ils font tous les deux référence à la même instance.

Au lieu de cela, vous devriez utiliser la méthode equals de ObjectID pour comparer leurs valeurs:

story._id.equals(offref.ref)

Comme @bendytree le note dans les commentaires, si l'une ou l'autre des valeurs peut être nulle (et que vous souhaitez que les valeurs nulles soient comparées égales), vous pouvez utiliser le code suivant:

String(story._id) === String(offref.ref)
83
JohnnyHK

Cela va un peu au-delà de la question initiale posée, mais j'ai constaté que la méthode .equals d'ObjectID retournera false dans certains cas où une comparaison de chaîne retournera true même si les valeurs ne sont pas nulles. Exemple:

var compare1 = invitationOwningUser.toString() === linkedOwningUser.toString();
var compare2 = invitationOwningUser.equals(linkedOwningUser);
var compare3 = String(invitationOwningUser) === String(linkedOwningUser);
logger.debug("compare1: " + compare1 + "; " + "compare2: " + compare2 + "; " + "compare3: " + compare3);

Sortie:

compare1: true; compare2: false; compare3: true 

Cela s'est produit lorsque invitationOwningUser (un ObjectID) provenait d'une collection créée à l'aide d'un schéma Mongoose et que linkedOwningUser (également un ObjectID) provenait d'une Collection non créée à l'aide de Mongoose (méthodes MongoDB ordinaires).

Voici le document contenant invitationOwningUser (le champ owningUser):

{
    "_id" : ObjectId("5782faec1f3b568d58d09518"),
    "owningUser" : ObjectId("5781a5685a06e69b158763ea"),
    "capabilities" : [
        "Read",
        "Update"
    ],
    "redeemed" : true,
    "expiry" : ISODate("2016-07-12T01:45:18.017Z"),
    "__v" : 0
}

Voici le document contenant linkedOwningUser (le champ owningUser):

{
    "_id" : ObjectId("05fb8257c95d538d58be7a89"),
    "linked" : [
        {
            "owningUser" : ObjectId("5781a5685a06e69b158763ea"),
            "capabilities" : [
                "Read",
                "Update"
            ]
        }
    ]
}

Donc, en bout de ligne, je vais utiliser la technique de comparaison de chaînes pour comparer les ID d'objet, pas la méthode .equals.

1
Chris Prince