123456789_123456789_123456789_123456789_123456789_

Module: Mongoid::Criteria::Includable

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Included In:
Defined in: lib/mongoid/criteria/includable.rb

Overview

Module providing functionality for parsing (nested) inclusion definitions.

Instance Attribute Summary

Instance Method Summary

Instance Attribute Details

#inclusionsArray<Mongoid::Association::Relatable> (rw)

Get a list of criteria that are to be executed for eager loading.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/criteria/includable.rb', line 59

def inclusions
  @inclusions ||= []
end

#inclusions=(value) ⇒ Array<Mongoid::Association::Relatable> (rw)

::Set the inclusions for the criteria.

Parameters:

Returns:

[ GitHub ]

  
# File 'lib/mongoid/criteria/includable.rb', line 68

def inclusions=(value)
  @inclusions = value
end

#use_lookup?true | false (readonly)

Returns whether to use $lookup aggregation for eager loading. Only when eager_load was requested and there is something to load: an empty inclusion list (e.g. eager_load([])) falls back to the normal path.

Returns:

  • (true | false)

    Whether to use $lookup.

[ GitHub ]

  
# File 'lib/mongoid/criteria/includable.rb', line 52

def use_lookup?
  !!@use_lookup && inclusions.any?
end

Instance Method Details

#add_inclusion(association, parent = nil) (private)

Add an inclusion definition to the list of inclusions for the criteria.

Parameters:

  • association (Mongoid::Association::Relatable)

    The association metadata.

  • parent (String) (defaults to: nil)

    The name of the association above this one in the inclusion tree, if it is a nested inclusion.

[ GitHub ]

  
# File 'lib/mongoid/criteria/includable.rb', line 79

def add_inclusion(association, parent = nil)
  if assoc = inclusions.detect { |a| a == association }
    assoc.parent_inclusions.push(parent) if parent
  else
    assoc = association.dup
    assoc.parent_inclusions = []
    assoc.parent_inclusions.push(parent) if parent
    inclusions.push(assoc)
  end
end

#eager_load(*relations) ⇒ Criteria

Eager loads all the provided associations using aggregation $lookup. The behavior should be identical to #includes.

Examples:

Eager load the provided associations.

Person.eager_load(:posts, :game)

Parameters:

  • *relations ([ Symbol | Hash ]...)

    The names of the association(s) to eager load.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/criteria/includable.rb', line 41

def eager_load(*relations)
  extract_includes_list(klass, nil, true, *relations)
  @use_lookup = !embedded?
  clone
end

#extract_includes_list(_parent_class, parent, is_eager_load = false, *relations_list) (private)

Iterate through the list of relations and create the inclusions list.

Parameters:

  • _parent_class (Class | String | Symbol)

    The class from which the association originates.

  • parent (String)

    The name of the association above this one in the inclusion tree, if it is a nested inclusion.

  • is_eager_load (Boolean) (defaults to: false)

    Whether this is an eager load operation.

  • *relations_list ([ Symbol | Hash | Array<Symbol | Hash> ]...)

    The names of the association(s) to eager load.

[ GitHub ]

  
# File 'lib/mongoid/criteria/includable.rb', line 99

def extract_includes_list(_parent_class, parent, is_eager_load = false, *relations_list)
  relations_list.flatten.each do |relation_object|
    # Normalize a bare association name to a hash with no nested
    # inclusions, so both forms share one resolution path below.
    relations = relation_object.is_a?(Hash) ? relation_object : { relation_object => nil }

    relations.each do |relation, nested|
      associations = resolve_inclusion_associations(_parent_class, relation, is_eager_load)
      raise_eager_error(is_eager_load, _parent_class, relation) if associations.empty?

      associations.each do |association|
        add_inclusion(association, parent)
        extract_includes_list(association.klass, association.name, is_eager_load, nested) if nested
      end
    end
  end
end

#includes(*relations) ⇒ Criteria

Note:

This will work for embedded associations that reference another collection via belongs_to as well.

Note:

Eager loading brings all the documents into memory, so there is a sweet spot on the performance gains. Internal benchmarks show that eager loading becomes slower around 100k documents, but this will naturally depend on the specific application.

Eager loads all the provided associations. Will load all the documents into the identity map whose ids match based on the extra query for the ids.

Examples:

Eager load the provided associations.

Person.includes(:posts, :game)

Parameters:

  • *relations ([ Symbol | Hash ]...)

    The names of the association(s) to eager load.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/criteria/includable.rb', line 26

def includes(*relations)
  extract_includes_list(klass, nil, false, *relations)
  clone
end

#resolve_inclusion_associations(parent_class, relation, is_eager_load) ⇒ Array<Mongoid::Association::Relatable> (private)

Resolve the association(s) matching the given relation name. For the regular #includes path, only the parent class is consulted. For the #eager_load ($lookup) path, its subclasses are consulted as well, so associations defined only on a subclass can also be eager-loaded when querying through the superclass.

Parameters:

  • parent_class (Class)

    The class to start the lookup from.

  • relation (Symbol | String)

    The association name.

  • is_eager_load (Boolean)

    Whether to consider subclasses.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/criteria/includable.rb', line 128

def resolve_inclusion_associations(parent_class, relation, is_eager_load)
  if association = parent_class.reflect_on_association(relation)
    return [ association ]
  end

  return [] unless is_eager_load

  parent_class.descendants.filter_map { |sub| sub.reflect_on_association(relation) }
end