_matches? does not account for comparison types

XMLWordPrintableJSON

    • Type: Bug
    • Resolution: Won't Fix
    • Priority: Critical - P2
    • None
    • Affects Version/s: None
    • Component/s: Query
    • None
    • None
    • Hide

      1. What would you like to communicate to the user about this feature?
      2. Would you like the user to see examples of the syntax and/or executable code and its output?
      3. Which versions of the driver/connector does this apply to?

      Show
      1. What would you like to communicate to the user about this feature? 2. Would you like the user to see examples of the syntax and/or executable code and its output? 3. Which versions of the driver/connector does this apply to?
    • None
    • None
    • None
    • None
    • None
    • None

      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.

            Assignee:
            Jamis Buck
            Reporter:
            Cameron Moreau
            Votes:
            0 Vote for this issue
            Watchers:
            9 Start watching this issue

              Created:
              Updated:
              Resolved: