I have a simple use case that used to work in my code, however now I've had to make changes to accommodate an issue I am now having. Looking to get some insights into why this has changed and requires extra check if anyone can help. My scenario is as described.
I have an array userBadgeIds
which holds the following: [ new ObjectId("59f347fca0f50c0004b5a3ac") ]
I used to do the following line: const exists = userBadgeIds.includes(badge._id)
which worked perfectly and told me if the input badge._id
was in the array. Both are mongoose ObjectId
so comparing equivalent in this way seemed perfect (again, it worked!).
However, for whatever reason I now have to compare them in the following way:
const exists = userBadgeIds.map(String).includes(badge._id.toString())
Now it works again. Is there something I'm missing about how the .includes
compares equivalence or something I'm missing about comparing ObjectId
specifically around ObjectId[]
?
CodePudding user response:
When you compare objects, they have to be the exact same object and not an object that has the same properties.
It's possible that something has changed in your code elsewhere or in a library that turns what was basically this:
const obj1 = { _id: 'a' };
const obj2 = { _id: 'b' };
const obj3 = { _id: 'c' };
const searchFor = obj1;
[obj1, obj2, obj3].includes(searchFor); // true
Into something that is essentially this:
const obj1 = { _id: 'a' };
const obj2 = { _id: 'b' };
const obj3 = { _id: 'c' };
const searchFor = { _id: 'a' };
[obj1, obj2, obj3].includes(searchFor); // false
searchFor
might have the same properties and prototype, but it's not the exact same object as obj1
. Perhaps some code is cloning badge
, making it not equal to the entries in the userBadgeIds
array.
Your workaround works, because when you compare strings, they don't have to be the exact same string, just have the same value.
As an aside, there's ObjectId.prototype.equals()
to compare two (identical or equivalent) ObjectIds.
// You need to pass searchFor as the second parameter to `some`
// so that `this` is correctly set.
[obj1, obj2, obj3].some(searchFor.equals, searchFor);
// Or you can do:
[obj1, obj2, obj3].some(searchFor.equals.bind(searchFor));
// Or:
[obj1, obj2, obj3].some(id => searchFor.equals(id));
Array.prototype.some
returns true
if any array entry matches the callback function, like includes
does for values.