Module: Mongoid::Association::EagerLoadable
- Defined in:
- lib/mongoid/association/eager_loadable.rb
Overview
This module defines the eager loading behavior for criteria.
Instance Method Summary collapse
-
#eager_load(docs) ⇒ Array<Mongoid::Document>
Load the associations for the given documents.
-
#eager_load_with_lookup ⇒ Array<Mongoid::Document>
Load the associations for the given documents using $lookup.
-
#eager_loadable? ⇒ true | false
Indicates whether the criteria has association inclusions which should be eager loaded.
-
#preload(associations, docs) ⇒ Object
Load the associations for the given documents.
-
#preload_for_lookup(criteria) ⇒ Array<Mongoid::Document>
Materialize the root documents with their inclusions eager-loaded by a single $lookup aggregation.
Instance Method Details
#eager_load(docs) ⇒ Array<Mongoid::Document>
Load the associations for the given documents.
25 26 27 28 29 |
# File 'lib/mongoid/association/eager_loadable.rb', line 25 def eager_load(docs) docs.tap do |d| preload(criteria.inclusions, d) if eager_loadable? end end |
#eager_load_with_lookup ⇒ Array<Mongoid::Document>
Load the associations for the given documents using $lookup.
If any of the associated collections reside in a different cluster or database than the root class, falls back to the #includes behavior and logs a warning.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/mongoid/association/eager_loadable.rb', line 38 def eager_load_with_lookup offenders = inclusions_unreachable_by_lookup if offenders.any? offender_descriptions = offenders.map do |offender| "#{offender.name} (client: #{offender.klass.client_name}, database: #{offender.klass.database_name})" end Mongoid.logger.warn( 'eager_load cannot use $lookup aggregation because the following associations ' \ "reside in a different cluster or database than #{klass} " \ "(client: #{klass.client_name}, database: #{klass.database_name}): " \ "#{offender_descriptions.join(', ')}. Falling back to #includes behavior." ) return eager_load(docs_for_lookup_fallback) end through_inclusions = criteria.inclusions.select do |association| association.is_a?(Association::Referenced::HasOneThrough) || association.is_a?(Association::Referenced::HasManyThrough) end if through_inclusions.any? through_names = through_inclusions.map { |association| ":#{association.name}" } Mongoid.logger.warn( "#{through_names.join(', ')} are :through associations and do not support " \ '$lookup-based eager loading. All inclusions for this query will be preloaded ' \ 'using separate queries.' ) return eager_load(docs_for_lookup_fallback) end documents = preload_for_lookup(criteria) # A polymorphic belongs_to cannot be expressed as a $lookup: its target # collection varies per document. It is resolved after the roots are # materialized, each inclusion by its own preloader. criteria.inclusions.select(&:polymorphic?).each do |association| EagerLoad::PolymorphicPreloader.new(association, klass).preload_into(documents) end documents end |
#eager_loadable? ⇒ true | false
Indicates whether the criteria has association inclusions which should be eager loaded.
16 17 18 |
# File 'lib/mongoid/association/eager_loadable.rb', line 16 def eager_loadable? !criteria.inclusions.empty? end |
#preload(associations, docs) ⇒ Object
Load the associations for the given documents. This will be done recursively to load the associations of the given documents' associated documents.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/mongoid/association/eager_loadable.rb', line 85 def preload(associations, docs) assoc_map = associations.group_by(&:inverse_class_name) docs_map = {} queue = [ klass.to_s ] # account for single-collection inheritance queue.push(klass.root_class.to_s) if klass != klass.root_class while klass = queue.shift next unless as = assoc_map.delete(klass) as.each do |assoc| queue << assoc.class_name # If this class is nested in the inclusion tree, only load documents # for the association above it. If there is no parent association, # we will include documents from the documents passed to this method. ds = docs ds = assoc.parent_inclusions.map { |p| docs_map[p].to_a }.flatten if assoc.parent_inclusions.length > 0 res = assoc.relation.eager_loader([ assoc ], ds).run docs_map[assoc.name] ||= [].to_set docs_map[assoc.name].merge(res) end end end |
#preload_for_lookup(criteria) ⇒ Array<Mongoid::Document>
Materialize the root documents with their inclusions eager-loaded by a single $lookup aggregation. The pipeline is built by LookupPipeline; the polymorphic inclusions it leaves out are resolved by the caller.
120 121 122 123 |
# File 'lib/mongoid/association/eager_loadable.rb', line 120 def preload_for_lookup(criteria) pipeline = EagerLoad::LookupPipeline.new(criteria).stages Eager.run(criteria.inclusions, [], true, pipeline) end |