Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose: ObjectId Comparisons fail inconsistently

I have a straightforward tool for building collections of documents and then automatically formatting them for EPUB or LaTeX rendering, written on top of ExpressJS. I'm using Coffeescript, if that matters (I doubt it).

Using Mongoose, I have the following:

DocumentSchema = new Schema     title:     String  Offrefs = new Schema     ref:       { type: ObjectId }     isa:       String  BinderSchema = new Schema     title:     String     contains:  [Offrefs] 

Offrefs doesn't specify what it refers to because because I want to be able to contain some binders in other binders, to create logical collections: "These are for the printer," "These are for epub," "These are web only," etc. (I've stripped out all the miscellaneous stuff out.)

Unfortunately, I have run into queries where, for retrieved objects

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

And the two do indeed look the same. But:

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

And a visual comparison of the two references in the last two, they are the same ID number, but the ObjectId objects don't compare correctly.

I don't want to have to do string conversions constantly, which is a strong possiblity when I'm converting these complex objects into trees of data. Tree relationships are a bear in any DB; they shouldn't be difficult in MongoDB.

How do you do ObjectId comparisons in MongoDB?

like image 976
Elf Sternberg Avatar asked Jun 16 '12 02:06

Elf Sternberg


People also ask

What is Mongoose schema types ObjectId?

A SchemaType is different from a type. In other words, mongoose.ObjectId !== mongoose.Types.ObjectId . A SchemaType is just a configuration object for Mongoose. An instance of the mongoose.ObjectId SchemaType doesn't actually create MongoDB ObjectIds, it is just a configuration for a path in a schema.

Can we overwrite Mongoose default ID with own id?

You can also overwrite Mongoose's default _id with your own _id . Just be careful: Mongoose will refuse to save a document that doesn't have an _id , so you're responsible for setting _id if you define your own _id path.

What is the difference between id and _ID in mongoose?

So, basically, the id getter returns a string representation of the document's _id (which is added to all MongoDB documents by default and have a default type of ObjectId ). Regarding what's better for referencing, that depends entirely on the context (i.e., do you want an ObjectId or a string ).

Is Mongoose _ID unique?

m has _id set. Does mongoose guarantee it's unique by querying mongo while creating model object? It does. One part of id is a random hash and another is a unique counter common accross collections.


2 Answers

A straight == (or ===) comparison will compare the two objects by reference, not value. So that will only evaluate to true if they both reference the very same instance.

Instead, you should be using the equals method of ObjectID to compare their values:

story._id.equals(offref.ref) 

As @bendytree notes in the comments, if either value could be null (and you want nulls to compare as equal), then you can use the following instead:

String(story._id) === String(offref.ref) 
like image 136
JohnnyHK Avatar answered Oct 04 '22 15:10

JohnnyHK


This goes somewhat beyond the original asked question, but I have found that the .equals method of ObjectID's will return false in some cases where a string comparison will return true even when the values are not null. Example:

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); 

Output:

compare1: true; compare2: false; compare3: true  

This occurred when invitationOwningUser (an ObjectID) came from a Collection created using a Mongoose schema, and linkedOwningUser (also an ObjectID) came from a Collection not created using Mongoose (just regular MongoDB methods).

Here is the document containing invitationOwningUser (the owningUser field):

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

Here is the document containing linkedOwningUser (the owningUser field):

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

So, as a bottom line for me, I'll be using the string comparison technique to compare ObjectID's, not the .equals method.

like image 37
Chris Prince Avatar answered Oct 04 '22 14:10

Chris Prince