skip to Main Content

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?

2

Answers


  1. 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 …

    Login or Signup to reply.
  2. 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 }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search