I believe that mongoid's function _matches? (in-memory comparison) should behave the same way a call to the database would. In the example below, I'll explain how I think _matches? is incorrectly casting values of the object, so that the type matches the comparison.
class User include Mongoid::Document # Key has the type of String, value can be any data type (String, Date, Bool, etc) # Example: {"y" => "this is a string"} # Another example: {"x" => 1, "y" => "this is a string", "z" => Time.parse("2023-05-01")} field :a, type: Hash end
Scenario 1
# Add a document where the hash value of "y" is a String user1 = User.create({ :a => { :y => "2023-05-01" } }) # Verify that the property is indeed a string user1[:a][:y].class # => String User.collection.find({}).first[:a][:y].class # => String # Selector is a filter on the "y" key inside the Hash "a" using a Time param selector = {"a.y" => {"$gt" => Time.parse("2023-04-02 06:59:59 UTC")}} # Mongo driver returns zero results using this selector User.collection.find(selector).count # => 0 # Using mongoid to run a query User.where(selector).count # => 0 # But the _matches? method in mongoid returns as matching # I believe the value here should be false since there was no match in the db user1._matches?(selector) # => true
Scenario 2
# Move the selector time into the future, still using Time as a param selector = {"a.y" => {"$gt" => Time.parse("2023-12-12 06:59:59 UTC")}} # Query still returns 0 as expected User.where(selector).count # => 0 # Mongoid now returns false, leading me to believe user1[:a][:y] is being coerced into Time user1._matches?(selector) # => false
Scenario 3
# Let's try again where user's "a.y" cannot be coerced to Time user2 = User.create({:a => { :y => "foo bar" }}) # Mongo driver still returns 0 as expected User.where(selector).count # => 0 # Mongoid as expected returns false user2._matches?(selector) # => false
I think the implicit coercion would be desired if the field we're working with was specified as Time, but in the case of a Hash - the type is unknown and seems to be returning incorrect results.