305

I have a node.js application that pulls some data and sticks it into an object, like this:

var results = new Object();

User.findOne(query, function(err, u) {
    results.userId = u._id;
}

When I do an if/then based on that stored ID, the comparison is never true:

if (results.userId == AnotherMongoDocument._id) {
    console.log('This is never true');
}

When I do a console.log of the two id's, they match exactly:

User id: 4fc67871349bb7bf6a000002 AnotherMongoDocument id: 4fc67871349bb7bf6a000002

I am assuming this is some kind of datatype problem, but I'm not sure how to convert results.userId to a datatype that will result in the above comparison being true and my outsourced brain (aka Google) has been unable to help.

Nahn
  • 3,196
  • 1
  • 24
  • 23
pat
  • 3,513
  • 3
  • 17
  • 20

9 Answers9

501

Mongoose uses the mongodb-native driver, which uses the custom ObjectID type. You can compare ObjectIDs with the .equals() method. With your example, results.userId.equals(AnotherMongoDocument._id). The ObjectID type also has a toString() method, if you wish to store a stringified version of the ObjectID in JSON format, or a cookie.

If you use ObjectID = require("mongodb").ObjectID (requires the mongodb-native library) you can check if results.userId is a valid identifier with results.userId instanceof ObjectID.

Etc.

cjohn
  • 11,370
  • 3
  • 30
  • 17
  • 25
    Docs for `.equals()`: http://mongodb.github.io/node-mongodb-native/api-bson-generated/objectid.html#equals – Anthony Panozzo Mar 06 '15 at 13:31
  • 5
    If you're already using `mongoose` you can just `require('mongoose').mongo.ObjectID` so you don't have to list any additional dependencies – JoshuaDavid Jul 14 '17 at 19:19
  • Latest doc: https://mongodb.github.io/node-mongodb-native/3.6/api/ObjectID.html – Poyoman Dec 07 '20 at 16:29
  • 2
    I've found doc._id == stringId also works, though of course doc._id === stringId will be false because of strict type comparison. This is just easier to code by. – Jat90 Mar 30 '21 at 10:56
82

ObjectIDs are objects so if you just compare them with == you're comparing their references. If you want to compare their values you need to use the ObjectID.equals method:

if (results.userId.equals(AnotherMongoDocument._id)) {
    ...
}
JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
38

converting object id to string(using toString() method) will do the job.

Dila Gurung
  • 1,726
  • 21
  • 26
20

The three possible solutions suggested here have different use cases.

  1. Use .equals when comparing ObjectId on two mongoDocuments like this
results.userId.equals(AnotherMongoDocument._id)
  1. Use .toString() when comparing a string representation of ObjectId to an ObjectId of a mongoDocument. like this
results.userId === AnotherMongoDocument._id.toString()
Antoni
  • 1,316
  • 2
  • 16
  • 42
Father-Empire
  • 539
  • 4
  • 9
14

According to the above,i found three ways to solve the problem.

  1. AnotherMongoDocument._id.toString()
  2. JSON.stringify(AnotherMongoDocument._id)
  3. results.userId.equals(AnotherMongoDocument._id)
joy
  • 141
  • 1
  • 2
8

The accepted answers really limit what you can do with your code. For example, you would not be able to search an array of Object Ids by using the equals method. Instead, it would make more sense to always cast to string and compare the keys.

Here's an example answer in case if you need to use indexOf() to check within an array of references for a specific id. assume query is a query you are executing, assume someModel is a mongo model for the id you are looking for, and finally assume results.idList is the field you are looking for your object id in.

query.exec(function(err,results){
   var array = results.idList.map(function(v){ return v.toString(); });
   var exists = array.indexOf(someModel._id.toString()) >= 0;
   console.log(exists);
});
r3wt
  • 4,642
  • 2
  • 33
  • 55
  • 1
    or a one-liner: `let exists = results.idList.filter(val => val.toString() === thisIsTheStringifiedIdWeAreLookingFor).length ? true : false` – Zlatko Jun 07 '16 at 20:12
  • 4
    @Zlatko i'm not a big fan of the new syntax but to each his own. – r3wt Jun 10 '16 at 04:09
  • 2
    @Zlatko `const exists = results.idList.some(val => val.toString() === thisIsTheStringifiedIdWeAreLookingFor)` or `const exists = results.idList.some(val => val.equals(someModel._id))` – axanpi Feb 10 '18 at 01:45
  • 1
    @Zlatko all these years later, and guess what. I prefer your version to mine now. mind if i add it to my answer with proper attribution? – r3wt Apr 04 '18 at 03:40
  • 1
    The price of progress :) Of course you can use the answer, it's purpose was to provide an alternative or help if possible. – Zlatko Apr 04 '18 at 06:45
3

I faced exactly the same problem and i simply resolved the issue with the help of JSON.stringify() as follow:-

if (JSON.stringify(results.userId) === JSON.stringify(AnotherMongoDocument._id)) {
        console.log('This is never true');
}
Jitendra
  • 3,135
  • 2
  • 26
  • 42
1

Mongoose from 5 to 6 migration guide:

"Mongoose now adds a valueOf() function to ObjectIds. This means you can now use == to compare an ObjectId against a string."

https://mongoosejs.com/docs/migrating_to_6.html#objectid-valueof

juliushuck
  • 1,398
  • 1
  • 11
  • 25
0

Here is an example that explains the issue and why it confusing for many. Only the first console log shows the object in its true form, and any other debuging/loging will be confusing because they look the same.

// Constructor for an object that has 'val' and some other stuffs
//   related to to librery...
function ID(_val) {
  this.val = _val;
  this.otherStuff = "other stuffs goes here";
}
// function to help user get usefull infos from the Object
ID.prototype.toString = function toString() {
  return `${this.val}`;
};
// Create new Object of type ID
const id = new ID('1234567');
console.log("my ID: ", id);  // my ID: Object { 
                             //    val: "1234567", 
                             //    otherStuff: "other stuffs goes here" 
                             // }

console.log("my ID: " + id); // my ID: 1234567
console.log(id === '1234567'); // false
console.log(id == '1234567'); // true
console.log(id.toString() === '1234567'); //true
console.log(`${id}` === '1234567'); // true
console.log(new ID('1234567') === id); // false
phoenixstudio
  • 1,776
  • 1
  • 14
  • 19