-
Type:
Bug
-
Resolution: Duplicate
-
Priority:
Unknown
-
None
-
Affects Version/s: None
-
Component/s: None
-
None
-
None
-
Ruby Drivers
-
None
-
None
-
None
-
None
-
None
-
None
When includes is called on a relation involving an inherited class, Mongoid 8 performs additional queries when accessing the related objects. This behavior can lead to inefficiencies, as demonstrated in the code example below.
require 'bundler/inline' gemfile do source 'https://rubygems.org' gem 'pry' gem 'pry-byebug' gem 'mongoid', '~> 8.0.8' # gem 'mongoid', '~> 7.5.4' end Mongoid.configure do |config| config.clients.default = { hosts: ['172.18.0.4:27017'], database: 'mongoid_test', } end Mongoid.purge! class Channel include Mongoid::Document has_many :tasks end class Task include Mongoid::Document belongs_to :channel end class ProcessingTask < Task end 3.times { ProcessingTask.create!(channel: Channel.create!) } Mongo::Logger.logger = Logger.new($stdout) Mongo::Logger.logger.level = Logger::DEBUG # Observations with Mongoid versions: # Mongoid 7.5.4: 2 queries # Mongoid 8.0.8: 5 queries ProcessingTask.includes(:channel).each do |task| pp task.channel&.id end # Consistent behavior (2 queries) across Mongoid versions Task.where(_type: 'ProcessingTask').includes(:channel).each do |task| pp task.channel&.id end
Example Output with Mongoid 8.0.8
When Calling ProcessingTask.includes(:channel):
The output shows that Mongoid performs multiple queries for the channel relation of ProcessingTask. Specifically, each ProcessingTask access results in a separate query to fetch the associated channel.
D, [2025-01-15T17:12:03.233685 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:14 conn:1:1 sconn:280 | mongoid_test.find | STARTED | {"find"=>"tasks", "filter"=>{"_type"=>"ProcessingTask"}, "$db"=>"mongoid_test", "lsid"=>{"id"=><BSON::Binary:0x2780 type=uuid data=0x64c54f1c5b454fb 9...>}} D, [2025-01-15T17:12:03.234118 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:14 | mongoid_test.find | SUCCEEDED | 0.000s D, [2025-01-15T17:12:03.234902 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:15 conn:1:1 sconn:280 | mongoid_test.find | STARTED | {"find"=>"channels", "filter"=>{"_id"=>BSON::ObjectId('6787de53797b7405357df0f1')}, "limit"=>1, "$db"=>"mongoid_test", "lsid"=>{"id"=><BSON::Binary:0x2780 type=uuid data=0x64c54f1c5b454fb9...>}} D, [2025-01-15T17:12:03.235129 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:15 | mongoid_test.find | SUCCEEDED | 0.000s BSON::ObjectId('6787de53797b7405357df0f1') D, [2025-01-15T17:12:03.235917 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:16 conn:1:1 sconn:280 | mongoid_test.find | STARTED | {"find"=>"channels", "filter"=>{"_id"=>BSON::ObjectId('6787de53797b7405357df0f3')}, "limit"=>1, "$db"=>"mongoid_test", "lsid"=>{"id"=><BSON::Binary:0x2780 type=uuid data=0x64c54f1c5b454fb9...>}} D, [2025-01-15T17:12:03.236150 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:16 | mongoid_test.find | SUCCEEDED | 0.000s BSON::ObjectId('6787de53797b7405357df0f3') D, [2025-01-15T17:12:03.236834 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:17 conn:1:1 sconn:280 | mongoid_test.find | STARTED | {"find"=>"channels", "filter"=>{"_id"=>BSON::ObjectId('6787de53797b7405357df0f5')}, "limit"=>1, "$db"=>"mongoid_test", "lsid"=>{"id"=><BSON::Binary:0x2780 type=uuid data=0x64c54f1c5b454fb9...>}} D, [2025-01-15T17:12:03.236990 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:17 | mongoid_test.find | SUCCEEDED | 0.000s BSON::ObjectId('6787de53797b7405357df0f5')
When Using Task.where(_type: 'ProcessingTask').includes(:channel):
In contrast, filtering explicitly by _type produces consistent query behavior across versions. Mongoid executes fewer queries by preloading all necessary relations in a single query.
D, [2025-01-15T17:12:03.237761 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:18 conn:1:1 sconn:280 | mongoid_test.find | STARTED | {"find"=>"tasks", "filter"=>{"_type"=>"ProcessingTask"}, "$db"=>"mongoid_test", "lsid"=>{"id"=><BSON::Binary:0x2780 type=uuid data=0x64c54f1c5b454fb 9...>}} D, [2025-01-15T17:12:03.237929 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:18 | mongoid_test.find | SUCCEEDED | 0.000s D, [2025-01-15T17:12:03.238399 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:19 conn:1:1 sconn:280 | mongoid_test.find | STARTED | {"find"=>"channels", "filter"=>{"_id"=>{"$in"=>[BSON::ObjectId('6787de53797b7405357df0f1'), BSON::ObjectId('6787de53797b7405357df0f3'), BSON::ObjectId('6787de53797b7405357df0f5')]}}, "$db"=>"mongoid_test", "lsid"=>{"id"=><BSON::Binary:0x2780 type=uuid... D, [2025-01-15T17:12:03.238609 #1333] DEBUG -- : MONGODB | 172.18.0.4:27017 req:19 | mongoid_test.find | SUCCEEDED | 0.000s BSON::ObjectId('6787de53797b7405357df0f1') BSON::ObjectId('6787de53797b7405357df0f3') BSON::ObjectId('6787de53797b7405357df0f5')
Key Takeaways
- Using includes directly with an inherited class like ProcessingTask can lead to additional queries when accessing related objects (channel).
- Filtering by _type explicitly (e.g., Task.where(_type: 'ProcessingTask')) ensures efficient preloading of relations.
- The behavior has changed between Mongoid versions (7.5.4 vs 8.0.8), with the latter performing more queries for the same operation.
- is depended on by
-
MONGOID-5839 Eager loading does not work for belongs_to with STI
-
- Closed
-