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

Mongoid 8.x performance and validation issues with belongs_to associations

      After updating to Mongoid 8 from 7.5 we noticed 2 problems with `belongs_to` associations:

      • performance issues
      • validation issues

      tl;dr - Mongoid 8 started to validate full chain of dependent objects.

      Here is simplified example (our real app scenario is way more complex):

      # MODELS
      
      class A
        include Mongoid::Document
        include Mongoid::Timestamps
      
        belongs_to :b
      end
      
      class B
        include Mongoid::Document
        include Mongoid::Timestamps
      
        has_one :a
        belongs_to :c
      end
      
      class C
        include Mongoid::Document
        include Mongoid::Timestamps
      
        has_one :b
        embeds_many :embs
      end
      
      class Emb
        include Mongoid::Document
        include Mongoid::Timestamps
      
        embedded_in :c
        belongs_to :d
      end
      
      class D
        include Mongoid::Document
        include Mongoid::Timestamps
      
        has_one :emb
      
        field :name, type: String
        validates :name, presence: true
      end 

       

      # SETUP
      
      ds = 20.times.map { D.create!(name: 'abc') }
      embs = ds.map { |d| Emb.new(d:) }
      c = C.create!(embs:)
      b = B.create!(c:) 

       

       

      Performance issue

       

      # TEST SCENARIO
      
      b = B.last
      a = A.create!(b:) 

      In Mongoid 7.5 you'll see only 2 mongo queries:

      | STARTED | {"find"=>"bs", ...
      | STARTED | {"insert"=>"as", ... 

      However in Mongoid 8.x it fetches the full chain of dependent objects which basically makes create action X times slower (depending on number of associations):

      | STARTED | {"find"=>"bs", ...
      | STARTED | {"find"=>"cs", ...
      | STARTED | {"find"=>"ds", ... x20
      | STARTED | {"insert"=>"as", ... 

      This approach looks incorrect. It's ok to validate 1st level associations but validating the whole chain could lead to a problems. Besides performance issues there is a chance that some record deep below has some validation errors which will lead to impossibility to save.

       

      Validation issue

      This works in 7.5, but doesn't work in 8:

       

      b = B.last
      b.c.embs.first.d.set(name: nil) # make record invalid
      exit
      
      b = B.last
      a = A.create!(b:) 

      Mongoid 8 will show:

       

       

      /Users/xxx/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/mongoid-8.1.3/lib/mongoid/persistable.rb:125:in `fail_due_to_validation!':  (Mongoid::Errors::Validations)
      message:
        Validation of A failed.
      summary:
        The following errors were found: B is invalid
      resolution:
        Try persisting the document with valid data or remove the validations.
       

      While Mongoid 7.5 will correctly create a record.

       

      It's a pretty common scenario when some record which was created N years ago is invalid. And that's fine. We are not touching or updating it. But this creates issues in places where you don't expect them. Certain parts of application start to trigger validation errors which are not related to the source of call.

      And obviously this happens when updating record and by just calling valid?.

       

      Additional notes:

      • Mongoid.belongs_to_required_by_default is true
      • all belongs_to assiciations are required and we can't change any of these options.

       

       

            Assignee:
            jamis.buck@mongodb.com Jamis Buck
            Reporter:
            shark55555@gmail.com Alexey Ramazanov
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: