Let say we have two objects of type NumberInt
in Mongo-Shell:
x = NumberInt(100)
y = NumberInt(100)
when I run the following comparisons, I am wondering why the last comparison is false
?
x == 100 // True
y == 100 // True
x == y // False! Why?
I did however expect to get false
by running the following lines:
x === y // False
x === 100 // False
x === 100 // False
which are false
as expected. Any idea?
CodePudding user response:
The main reason is that equality operators work for primitive values , but not for objects and the function NumberInt() is defining object in the mongoshell:
mongos> x=100
100
mongos> typeof x
number
mongos> y=NumberInt(100)
NumberInt(100)
mongos> typeof y
object
One option to compare the values in objects is to flatten the values to string via the JSON.stringify() in the mongoshell and then compare:
mongos> JSON.stringify(x)===JSON.stringify(y)
true
mongos>
Note that when you insert the NumberInt(100) object to mongoDB it is converted to integer and if you read it back it is not an object but a number type:
mongos> db.test.insert({a:y})
WriteResult({ "nInserted" : 1 })
mongos> db.test.find()
{ "_id" : ObjectId("6292a16069154745fd5f93c3"), "a" : 100 }
mongos> db.test.aggregate([ {$project:{aType:{"$type":"$a" }}} ])
{ "_id" : ObjectId("6292a16069154745fd5f93c3"), "aType" : "int" }
mongos> var z = db.test.findOne({})
mongos> typeof z.a
number
mongos>
Which mean that if you read the value from mongoDB you can compare with the equality operator without an issue ...
CodePudding user response:
I haven't found exact answer, but I guess the below mostly answers on this question. To understand we can look at ObjectId
implementation and comparison operators you used.
MongoDB Enterprise replset:PRIMARY> o1 = ObjectId("507f1f77bcf86cd799439011")
ObjectId("507f1f77bcf86cd799439011")
MongoDB Enterprise replset:PRIMARY> o2 = ObjectId("507f1f77bcf86cd799439011")
ObjectId("507f1f77bcf86cd799439011")
MongoDB Enterprise replset:PRIMARY> o1.equals(o2)
true
MongoDB Enterprise replset:PRIMARY> o1 == o2 # your case 1
false
MongoDB Enterprise replset:PRIMARY> o1 === o2 # your case 2
false
The reason of this behavior is in equals
implementation that you can see if you simply write a method name without ()
:
MongoDB Enterprise replset:PRIMARY> o1.equals
function(other) {
return this.str == other.str;
}
notice that actual comparing happens not with this
(which is ObjectId) but with some field inside:
MongoDB Enterprise replset:PRIMARY> o1.str == o2.str
true
I think something similar happens with NumberInt as well, I just didn't find it yet.
Notice2, that it doesn't affect querying functionality that just simply works:
MongoDB Enterprise replset:PRIMARY> db.coll.insertOne({a : NumberInt(100), b : NumberInt(100)})
{
"acknowledged" : true,
"insertedId" : ObjectId("62928aae53867e1d4ea6cee4")
}
MongoDB Enterprise replset:PRIMARY> db.coll.find({ $expr: {$eq: ["$a", "$b"]}})
{ "_id" : ObjectId("62928aae53867e1d4ea6cee4"), "a" : 100, "b" : 100 }