Uploaded image for project: 'Mongoid'
  1. Mongoid
  2. MONGOID-4860

Document Foo.or(...) -> Foo.and(Foo.or(...)) migration path

    • Type: Icon: Improvement Improvement
    • Resolution: Duplicate
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: 7.1.0
    • Component/s: Docs, Query
    • None

      Hello, I just tried updating from 7.0.5 to 7.1.0 and the problem is after reading the latest Mongoid doc about the new way selectors works, I'm still haven't found a way to rewrite my first broken selector, here is how it looks:

      I have a has_many relation, through which I want to do a OR between two clauses, I used to do it with model.relation.any_of({}, {}), but since 7.1.0 the $or clauses includes the relation criteria too (model_id) which is clearly not what I want.

      Here is a running example:

      require 'mongoid'
      
      Mongoid.configure do |config|
        config.clients.default = {
          hosts: ['localhost:27017'],
          database: 'test',
        }
      end
      Mongo::Logger.logger.level = :warn
      
      class User
        include Mongoid::Document
        has_many :comments
      end
      
      class Comment
        include Mongoid::Document
        belongs_to :user, optional: true
        field :time, type: Integer
      end
      
      user = User.first || User.create!
      Comment.delete_all
      user.comments.create! time: 2
      user.comments.create! time: 4
      user.comments.create! time: 8    # ← should return
      user.comments.create! time: nil  # ← should return
      Comment.create! time: nil
      Comment.create! time: 8
      
      p Mongoid::VERSION
      puts "expect 2, got #{user.comments.any_of({:time.gt => 5}, {:time => nil}).count}, criteria:"
      p user.comments.any_of({:time.gt => 5}, {:time => nil}).selector
      
      # Mongoid 7.0.5 (ok)
      # expect 2, got 2, criteria:
      # {"user_id"=>BSON::ObjectId('5e740088b2c79a527394bf4d'), "$or"=>[{"time"=>{"$gt"=>5}}, {"time"=>nil}]}
      
      # Mongoid 7.1.0 (not what I wanted)
      # expect 2, got 6, criteria:
      # {"$or"=>[{"user_id"=>BSON::ObjectId('5e740088b2c79a527394bf4d')}, {"time"=>{"$gt"=>5}}, {"time"=>nil}]}
      
      # Also tried:
      puts "expect 2, got #{user.comments.gt(time: 5).or(time: nil).count}, criteria:"
      p user.comments.gt(time: 5).or(time: nil).selector
      
      # Mongoid 7.0.5 (not what I wanted)
      # expect 2, got 0, criteria:
      # {"user_id"=>BSON::ObjectId('5e740088b2c79a527394bf4d'), "time"=>{"$gt"=>5}, "$or"=>[{"time"=>nil}]}
      
      # Mongoid 7.1.0 (not what I wanted)
      # expect 2, got 3, criteria:
      # {"$or"=>[{"user_id"=>BSON::ObjectId('5e740088b2c79a527394bf4d'), "time"=>{"$gt"=>5}}, {"time"=>nil}]}
      

      How am I supposed to write this query now? I saw in the doc "When a logical operator is used, it operates on the criteria built up to that point and its argument" but the thing is it's a relation here I can't just put the or before the relation.

      See MONGOID-4697 for the implementation of these changes and MONGOID-4855 for discussions about "any_of" vs "or".

            Assignee:
            oleg.pudeyev@mongodb.com Oleg Pudeyev (Inactive)
            Reporter:
            bigbourin@gmail.com Adrien Jarthon
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: