123456789_123456789_123456789_123456789_123456789_

Class: Mongoid::Contextual::Mongo

Relationships & Source Files
Namespace Children
Classes:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Forwardable
Instance Chain:
Inherits: Object
Defined in: lib/mongoid/contextual/mongo.rb,
lib/mongoid/contextual/mongo/documents_loader.rb

Overview

Context object used for performing bulk query and persistence operations on documents which are persisted in the database and have not been loaded into application memory.

Constant Summary

::Mongoid::Atomic - Included

UPDATES

::Mongoid::Atomic - Attributes & Methods

  • #_index rw

    When MongoDB finally fully implements the positional operator, we can get rid of all indexing related code in ::Mongoid.

Class Method Summary

Instance Attribute Summary

Queryable - Included

::Mongoid::Association::EagerLoadable - Included

#eager_loadable?

Indicates whether the criteria has association inclusions which should be eager loaded.

Instance Method Summary

::Mongoid::Association::EagerLoadable - Included

#eager_load

Load the associations for the given documents.

#preload

Load the associations for the given documents.

::Mongoid::Atomic - Included

#_updates
#add_atomic_pull

Add the document as an atomic pull.

#add_atomic_unset

Add an atomic unset for the document.

#atomic_array_add_to_sets

For array fields these are the unique adds that need to happen.

#atomic_array_pulls

For array fields these are the pulls that need to happen.

#atomic_array_pushes

For array fields these are the pushes that need to happen.

#atomic_attribute_name

Returns path of the attribute for modification.

#atomic_delete_modifier

Get the removal modifier for the document.

#atomic_insert_modifier

Get the insertion modifier for the document.

#atomic_path

Return the path to this Document in JSON notation, used for atomic updates via $set in MongoDB.

#atomic_paths

Get the atomic paths utility for this document.

#atomic_position

Returns the positional operator of this document for modification.

#atomic_pulls

Get all the attributes that need to be pulled.

#atomic_pushes

Get all the push attributes that need to occur.

#atomic_sets

Get all the attributes that need to be set.

#atomic_unsets

Get all the attributes that need to be unset.

#atomic_updates

Get all the atomic updates that need to happen for the current Document.

#delayed_atomic_pulls

Get a hash of atomic pulls that are pending.

#delayed_atomic_sets

Get all the atomic sets that have had their saves delayed.

#delayed_atomic_unsets

Get the delayed atomic unsets.

#flag_as_destroyed

Flag the document as destroyed and return the atomic path.

#flagged_destroys

Get the flagged destroys.

#process_flagged_destroys

Process all the pending flagged destroys from nested attributes.

#generate_atomic_updates

Generates the atomic updates in the correct order.

#reset_atomic_updates!

Clears all pending atomic updates.

Aggregable::Mongo - Included

#aggregates

Get all the aggregate values for the provided field.

#avg

Get the average value of the provided field.

#max

Get the max value of the provided field.

#min

Get the min value of the provided field.

#sum

Get the sum value of the provided field.

#pipeline

Get the aggregation pipeline for provided field.

Constructor Details

.new(criteria) ⇒ Mongo

Create the new Mongo context. This delegates operations to the underlying driver.

Examples:

Create the new context.

Mongo.new(criteria)

Parameters:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 270

def initialize(criteria)
  @criteria, @klass = criteria, criteria.klass
  @collection = @klass.collection
  criteria.send(:merge_type_selection)
  @view = collection.find(criteria.selector, session: _session)
  apply_options
end

Instance Attribute Details

#_index (rw)

When MongoDB finally fully implements the positional operator, we can get rid of all indexing related code in ::Mongoid.

[ GitHub ]

  
# File 'lib/mongoid/atomic.rb', line 25

attr_accessor :_index

#acknowledged_write?Boolean (readonly, private)

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 892

def acknowledged_write?
  collection.write_concern.nil? || collection.write_concern.acknowledged?
end

#documents_loader (readonly)

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 54

attr_reader :documents_loader

#viewHash (readonly)

Run an explain on the criteria.

Examples:

Explain the criteria.

Band.where(name: "Depeche Mode").explain

Parameters:

  • options (Hash)

    customizable options (See Mongo::Collection::View::Explainable)

Returns:

  • (Hash)

    The explain result.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 42

attr_reader :view

#view The Mongo collection view.(The Mongo collection view.) (readonly)

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 42

attr_reader :view

Instance Method Details

#_session (private)

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 888

def _session
  @criteria.send(:_session)
end

#apply_fields (private)

This method is for internal use only.

Apply the field limitations.

Examples:

Apply the field limitations.

context.apply_fields
[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 805

def apply_fields
  if spec = criteria.options[:fields]
    @view = view.projection(spec)
  end
end

#apply_option(name) (private)

This method is for internal use only.

Apply an option.

Examples:

Apply the skip option.

context.apply_option(:skip)
[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 833

def apply_option(name)
  if spec = criteria.options[name]
    @view = view.send(name, spec)
  end
end

#apply_options (private)

This method is for internal use only.

Apply the options.

Examples:

Apply all options.

context.apply_options
[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 817

def apply_options
  apply_fields
  OPTIONS.each do |name|
    apply_option(name)
  end
  if criteria.options[:timeout] == false
    @view = view.no_cursor_timeout
  end
end

#count(options = {}, &block) ⇒ Integer

Get the number of documents matching the query.

Examples:

Get the number of matching documents.

context.count

Get the count of documents with the provided options.

context.count(limit: 1)

Get the count for where the provided block is true.

context.count do |doc|
  doc.likes > 1
end

Parameters:

  • options (Hash) (defaults to: {})

    The options, such as skip and limit to be factored into the count.

Returns:

  • (Integer)

    The number of matches.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 73

def count(options = {}, &block)
  return super(&block) if block_given?

  if valid_for_count_documents?
    view.count_documents(options)
  else
    # TODO: Remove this when we remove the deprecated for_js API.
    # https://jira.mongodb.org/browse/MONGOID-5681
    view.count(options)
  end
end

#deletenil Also known as: #delete_all

Delete all documents in the database that match the selector.

Examples:

Delete all the documents.

context.delete

Returns:

  • (nil)

    Nil.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 114

def delete
  view.delete_many.deleted_count
end

#delete_all

Alias for #delete.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 117

alias :delete_all :delete

#demongoize_with_field(field, value, is_translation) ⇒ Object (private)

This method is for internal use only.

Demongoize the value for the given field. If the field is nil or the field is a translations field, the value is demongoized using its class.

Parameters:

  • field (Field)

    The field to use to demongoize.

  • value (Object)

    The value to demongoize.

  • is_translation (true | false)

    The field we are retrieving is an _translations field.

Returns:

  • (Object)

    The demongoized value.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 993

def demongoize_with_field(field, value, is_translation)
  if field
    # If it's a localized field that's not a hash, don't demongoize
    # again, we already have the translation. If it's an _translations
    # field, don't demongoize, we want the full hash not just a
    # specific translation.
    # If it is a hash, and it's not a translations field, we need to
    # demongoize to get the correct translation.
    if field.localized? && (!value.is_a?(Hash) || is_translation)
      value.class.demongoize(value)
    else
      field.demongoize(value)
    end
  else
    value.class.demongoize(value)
  end
end

#destroynil Also known as: #destroy_all

Destroy all documents in the database that match the selector.

Examples:

Destroy all the documents.

context.destroy

Returns:

  • (nil)

    Nil.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 125

def destroy
  each.inject(0) do |count, doc|
    doc.destroy
    count += 1 if acknowledged_write?
    count
  end
end

#destroy_all

Alias for #destroy.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 132

alias :destroy_all :destroy

#distinct(field) ⇒ Array<Object>

Get the distinct values in the db for the provided field.

Examples:

Get the distinct values.

context.distinct(:name)

Parameters:

Returns:

  • (Array<Object>)

    The distinct values for the field.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 142

def distinct(field)
  name = klass.cleanse_localized_field_names(field)

  view.distinct(name).map do |value|
    is_translation = "#{name}_translations" == field.to_s
    recursive_demongoize(name, value, is_translation)
  end
end

#documents_for_iterationArray<Document> | Mongo::Collection::View (private)

This method is for internal use only.

Get the documents the context should iterate.

If the documents have been already preloaded by ‘Document::Loader` instance, they will be used.

Returns:

  • (Array<Document> | Mongo::Collection::View)

    The docs to iterate.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 855

def documents_for_iteration
  if @documents_loader
    if @documents_loader.started?
      @documents_loader.value!
    else
      @documents_loader.unschedule
      @documents_loader.execute
    end
  else
    return view unless eager_loadable?
    docs = view.map do |doc|
      Factory.from_db(klass, doc, criteria)
    end
    eager_load(docs)
  end
end

#each(&block) ⇒ Enumerator

Iterate over the context. If provided a block, yield to a ::Mongoid document for each, otherwise return an enum.

Examples:

Iterate over the context.

context.each do |doc|
  puts doc.name
end

Returns:

  • (Enumerator)

    The enumerator.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 160

def each(&block)
  if block_given?
    documents_for_iteration.each do |doc|
      yield_document(doc, &block)
    end
    self
  else
    to_enum
  end
end

#estimated_count(options = {}) ⇒ Integer

Get the estimated number of documents matching the query.

Unlike count, estimated_count does not take a block because it is not traditionally defined (with a block) on Enumarable like count is.

Examples:

Get the estimated number of matching documents.

context.estimated_count

Parameters:

  • options (Hash) (defaults to: {})

    The options, such as maxTimeMS to be factored into the count.

Returns:

  • (Integer)

    The number of matches.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 97

def estimated_count(options = {})
  unless self.criteria.selector.empty?
    if klass.default_scoping?
      raise Mongoid::Errors::InvalidEstimatedCountScoping.new(self.klass)
    else
      raise Mongoid::Errors::InvalidEstimatedCountCriteria.new(self.klass)
    end
  end
  view.estimated_document_count(options)
end

#exists?(id_or_conditions = :none) ⇒ true | false

Note:

We don’t use count here since Mongo does not use counted b-tree indexes.

Do any documents exist for the context.

Examples:

Do any documents exist for the context.

context.exists?

Do any documents exist for given _id.

context.exists?(BSON::ObjectId(...))

Do any documents exist for given conditions.

context.exists?(name: "...")

Parameters:

  • id_or_conditions (Hash | Object | false) (defaults to: :none)

    an _id to search for, a hash of conditions, nil or false.

Returns:

  • (true | false)

    If the count is more than zero. Always false if passed nil or false.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 190

def exists?(id_or_conditions = :none)
  return false if self.view.limit == 0
  case id_or_conditions
  when :none then !!(view.projection(_id: 1).limit(1).first)
  when nil, false then false
  when Hash then Mongo.new(criteria.where(id_or_conditions)).exists?
  else Mongo.new(criteria.where(_id: id_or_conditions)).exists?
  end
end

#extract_value(attrs, field_name) (private)

Extracts the value for the given field name from the given attribute hash.

Parameters:

  • attrs (Hash)

    The attributes hash.

  • field_name (String)

    The name of the field to extract.

  • The (Object)

    value for the given field name

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 923

def extract_value(attrs, field_name)
  i = 1
  num_meths = field_name.count('.') + 1
  curr = attrs.dup

  klass.traverse_association_tree(field_name) do |meth, obj, is_field|
    field = obj if is_field
    is_translation = false
    # If no association or field was found, check if the meth is an
    # _translations field.
    if obj.nil? & tr = meth.match(/(.*)_translations\z/)&.captures&.first
      is_translation = true
      meth = tr
    end

    # 1. If curr is an array fetch from all elements in the array.
    # 2. If the field is localized, and is not an _translations field
    #    (_translations fields don't show up in the fields hash).
    #    - If this is the end of the methods, return the translation for
    #      the current locale.
    #    - Otherwise, return the whole translations hash so the next method
    #      can select the language it wants.
    # 3. If the meth is an _translations field, do not demongoize the
    #    value so the full hash is returned.
    # 4. Otherwise, fetch and demongoize the value for the key meth.
    curr = if curr.is_a? Array
      res = fetch_and_demongoize(curr, meth, field)
      res.empty? ? nil : res
    elsif !is_translation && field&.localized?
      if i < num_meths
        curr.try(:fetch, meth, nil)
      else
        fetch_and_demongoize(curr, meth, field)
      end
    elsif is_translation
      curr.try(:fetch, meth, nil)
    else
      fetch_and_demongoize(curr, meth, field)
    end

    i += 1
  end
  curr
end

#fetch_and_demongoize(obj, meth, field) ⇒ Object (private)

This method is for internal use only.

Fetch the element from the given hash and demongoize it using the given field. If the obj is an array, map over it and call this method on all of its elements.

Parameters:

  • obj (Hash | Array<Hash>)

    The hash or array of hashes to fetch from.

  • meth (String)

    The key to fetch from the hash.

  • field (Field)

    The field to use for demongoization.

Returns:

  • (Object)

    The demongoized value.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 907

def fetch_and_demongoize(obj, meth, field)
  if obj.is_a?(Array)
    obj.map { |doc| fetch_and_demongoize(doc, meth, field) }
  else
    res = obj.try(:fetch, meth, nil)
    field ? field.demongoize(res) : res.class.demongoize(res)
  end
end

#fifthDocument | nil

Get the fifth document in the database for the criteria’s selector.

Examples:

Get the fifth document.

context.fifth

Returns:

  • (Document | nil)

    The fifth document or nil if none is found.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 699

def fifth
  retrieve_nth(4)
end

#fifth!Document

Get the fifth document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the fifth document.

context.fifth!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 713

def fifth!
  fifth || raise_document_not_found_error
end

#find_first

This method is for internal use only.

Return the first result without applying sort

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 256

def find_first
  if raw_doc = view.first
    doc = Factory.from_db(klass, raw_doc, criteria)
    eager_load([doc]).first
  end
end

#find_one_and_deleteDocument

Execute the find and modify command, used for MongoDB’s $findAndModify. This deletes the found document.

Examples:

Execute the command.

context.find_one_and_delete

Returns:

  • (Document)

    The result of the command.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 247

def find_one_and_delete
  if doc = view.find_one_and_delete
    Factory.from_db(klass, doc)
  end
end

#find_one_and_replace(replacement, options = {}) ⇒ Document

Execute the find and modify command, used for MongoDB’s $findAndModify.

Examples:

Execute the command.

context.find_one_and_update({ likes: 1 })

Parameters:

  • replacement (Hash)

    The replacement.

  • options (Hash) (defaults to: {})

    The command options.

Options Hash (options):

  • :return_document (:before | :after)

    Return the updated document from before or after update.

  • :upsert (true | false)

    Create the document if it doesn’t exist.

Returns:

  • (Document)

    The result of the command.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 234

def find_one_and_replace(replacement, options = {})
  if doc = view.find_one_and_replace(replacement, options)
    Factory.from_db(klass, doc)
  end
end

#find_one_and_update(update, options = {}) ⇒ Document

Execute the find and modify command, used for MongoDB’s $findAndModify.

Examples:

Execute the command.

context.find_one_and_update({ "$inc" => { likes: 1 }})

Parameters:

  • update (Hash)

    The updates.

  • options (Hash) (defaults to: {})

    The command options.

Options Hash (options):

  • :return_document (:before | :after)

    Return the updated document from before or after update.

  • :upsert (true | false)

    Create the document if it doesn’t exist.

Returns:

  • (Document)

    The result of the command.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 214

def find_one_and_update(update, options = {})
  if doc = view.find_one_and_update(update, options)
    Factory.from_db(klass, doc)
  end
end

#first(limit = nil) ⇒ Document | nil Also known as: #one

Note:

Automatically adding a sort on _id when no other sort is defined on the criteria has the potential to cause bad performance issues. If you experience unexpected poor performance when using #first or #last and have no sort defined on the criteria, use #take instead. Be aware that #take won’t guarantee order.

Get the first document in the database for the criteria’s selector.

Examples:

Get the first document.

context.first

Parameters:

  • limit (Integer) (defaults to: nil)

    The number of documents to return.

Returns:

  • (Document | nil)

    The first document or nil if none is found.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 550

def first(limit = nil)
  if limit.nil?
    retrieve_nth(0)
  else
    retrieve_nth_with_limit(0, limit)
  end
end

#first!Document

Note:

Automatically adding a sort on _id when no other sort is defined on the criteria has the potential to cause bad performance issues. If you experience unexpected poor performance when using #first! or #last! and have no sort defined on the criteria, use #take! instead. Be aware that #take! won’t guarantee order.

Get the first document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the first document.

context.first!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 575

def first!
  first || raise_document_not_found_error
end

#fourthDocument | nil

Get the fourth document in the database for the criteria’s selector.

Examples:

Get the fourth document.

context.fourth

Returns:

  • (Document | nil)

    The fourth document or nil if none is found.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 675

def fourth
  retrieve_nth(3)
end

#fourth!Document

Get the fourth document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the fourth document.

context.fourth!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 689

def fourth!
  fourth || raise_document_not_found_error
end

#inverse_sorting (private)

This method is for internal use only.

Map the inverse sort symbols to the correct MongoDB values.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 842

def inverse_sorting
  sort = view.sort || { _id: 1 }
  Hash[sort.map{|k, v| [k, -1*v]}]
end

#last(limit = nil) ⇒ Document | nil

Note:

Automatically adding a sort on _id when no other sort is defined on the criteria has the potential to cause bad performance issues. If you experience unexpected poor performance when using #first or #last and have no sort defined on the criteria, use #take instead. Be aware that #take won’t guarantee order.

Get the last document in the database for the criteria’s selector.

Examples:

Get the last document.

context.last

Parameters:

  • limit (Integer) (defaults to: nil)

    The number of documents to return.

Returns:

  • (Document | nil)

    The last document or nil if none is found.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 593

def last(limit = nil)
  if limit.nil?
    retrieve_nth_to_last(0)
  else
    retrieve_nth_to_last_with_limit(0, limit)
  end
end

#last!Document

Note:

Automatically adding a sort on _id when no other sort is defined on the criteria has the potential to cause bad performance issues. If you experience unexpected poor performance when using #first! or #last! and have no sort defined on the criteria, use #take! instead. Be aware that #take! won’t guarantee order.

Get the last document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the last document.

context.last!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 617

def last!
  last || raise_document_not_found_error
end

#lengthInteger Also known as: #size

Returns the number of documents in the database matching the query selector.

Examples:

Get the length.

context.length

Returns:

  • (Integer)

    The number of documents.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 287

def length
  self.count
end

#limit(value) ⇒ Mongo

Limits the number of documents that are returned from the database.

Examples:

Limit the documents.

context.limit(20)

Parameters:

  • value (Integer)

    The number of documents to return.

Returns:

  • (Mongo)

    The context.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 300

def limit(value)
  @view = view.limit(value) and self
end

#load_async

This method is for internal use only.

Schedule a task to load documents for the context.

Depending on the ::Mongoid configuration, the scheduled task can be executed immediately on the caller’s thread, or can be scheduled for an asynchronous execution.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 776

def load_async
  @documents_loader ||= DocumentsLoader.new(view, klass, criteria)
end

#map_reduce(map, reduce) ⇒ MapReduce

Initiate a map/reduce operation from the context.

Examples:

Initiate a map/reduce.

context.map_reduce(map, reduce)

Parameters:

  • map (String)

    The map js function.

  • reduce (String)

    The reduce js function.

Returns:

  • (MapReduce)

    The map/reduce lazy wrapper.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 313

def map_reduce(map, reduce)
  MapReduce.new(collection, criteria, map, reduce)
end

#one(limit = nil)

Alias for #first.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 557

alias :one :first

#pick(*fields) ⇒ Object | Array<Object>

Pick the single field values from the database.

Examples:

Pick a field.

context.pick(:_id)

Parameters:

Returns:

  • (Object | Array<Object>)

    The picked values.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 361

def pick(*fields)
  limit(1).pluck(*fields).first
end

#pluck(*fields) ⇒ Array<Object> | Array<Array<Object>>

Pluck the field value(s) from the database. Returns one result for each document found in the database for the context. The results are normalized according to their ::Mongoid field types. Note that the results may include duplicates and nil values.

Examples:

Pluck a field.

context.pluck(:_id)

Parameters:

  • *fields ([ String | Symbol ]...)

    Field(s) to pluck, which may include nested fields using dot-notation.

Returns:

  • (Array<Object> | Array<Array<Object>>)

    The plucked values. If the *fields arg contains a single value, each result in the array will be a single value. Otherwise, each result in the array will be an array of values.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 333

def pluck(*fields)
  # Multiple fields can map to the same field name. For example, plucking
  # a field and its _translations field map to the same field in the database.
  # because of this, we need to keep track of the fields requested.
  normalized_field_names = []
  normalized_select = fields.inject({}) do |hash, f|
    db_fn = klass.database_field_name(f)
    normalized_field_names.push(db_fn)
    hash[klass.cleanse_localized_field_names(f)] = true
    hash
  end

  view.projection(normalized_select).reduce([]) do |plucked, doc|
    values = normalized_field_names.map do |n|
      extract_value(doc, n)
    end
    plucked << (values.size == 1 ? values.first : values)
  end
end

#process_raw_docs(raw_docs, limit) ⇒ Array<Document> | Document (private)

Process the raw documents retrieved for #first/#last.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 1015

def process_raw_docs(raw_docs, limit)
  docs = raw_docs.map do |d|
    Factory.from_db(klass, d, criteria)
  end
  docs = eager_load(docs)
  limit ? docs : docs.first
end

#raise_document_not_found_error (private)

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 1044

def raise_document_not_found_error
  raise Errors::DocumentNotFound.new(klass, nil, nil)
end

#recursive_demongoize(field_name, value, is_translation) ⇒ Object (private)

Recursively demongoize the given value. This method recursively traverses the class tree to find the correct field to use to demongoize the value.

Parameters:

  • field_name (String)

    The name of the field to demongoize.

  • value (Object)

    The value to demongoize.

  • is_translation (true | false)

    The field we are retrieving is an _translations field.

Returns:

  • (Object)

    The demongoized value.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 977

def recursive_demongoize(field_name, value, is_translation)
  field = klass.traverse_association_tree(field_name)
  demongoize_with_field(field, value, is_translation)
end

#retrieve_nth(n) (private)

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 1048

def retrieve_nth(n)
  retrieve_nth_with_limit(n, 1).first
end

#retrieve_nth_to_last(n) (private)

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 1061

def retrieve_nth_to_last(n)
  retrieve_nth_to_last_with_limit(n, 1).first
end

#retrieve_nth_to_last_with_limit(n, limit) (private)

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 1065

def retrieve_nth_to_last_with_limit(n, limit)
  v = view.sort(inverse_sorting).skip(n).limit(limit || 1)
  v = v.skip(n) if n > 0
  raw_docs = v.to_a.reverse
  process_raw_docs(raw_docs, limit)
end

#retrieve_nth_with_limit(n, limit) (private)

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 1052

def retrieve_nth_with_limit(n, limit)
  sort = view.sort || { _id: 1 }
  v = view.sort(sort).limit(limit || 1)
  v = v.skip(n) if n > 0
  if raw_docs = v.to_a
    process_raw_docs(raw_docs, limit)
  end
end

#secondDocument | nil

Get the second document in the database for the criteria’s selector.

Examples:

Get the second document.

context.second

Returns:

  • (Document | nil)

    The second document or nil if none is found.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 627

def second
  retrieve_nth(1)
end

#second!Document

Get the second document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the second document.

context.second!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 641

def second!
  second || raise_document_not_found_error
end

#second_to_lastDocument | nil

Get the second to last document in the database for the criteria’s selector.

is found.

Examples:

Get the second to last document.

context.second_to_last

Returns:

  • (Document | nil)

    The second to last document or nil if none

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 725

def second_to_last
  retrieve_nth_to_last(1)
end

#second_to_last!Document

Get the second to last document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the second to last document.

context.second_to_last!

Returns:

  • (Document)

    The second to last document.

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 739

def second_to_last!
  second_to_last || raise_document_not_found_error
end

#size

Alias for #length.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 290

alias :size :length

#skip(value) ⇒ Mongo

Skips the provided number of documents.

Examples:

Skip the documents.

context.skip(20)

Parameters:

  • value (Integer)

    The number of documents to skip.

Returns:

  • (Mongo)

    The context.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 480

def skip(value)
  @view = view.skip(value) and self
end

#sort(values = nil, &block) ⇒ Mongo

Sorts the documents by the provided spec.

Examples:

Sort the documents.

context.sort(name: -1, title: 1)

Parameters:

  • values (Hash) (defaults to: nil)

    The sorting values as field/direction(1/-1) pairs.

Returns:

  • (Mongo)

    The context.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 493

def sort(values = nil, &block)
  if block_given?
    super(&block)
  else
    # update the criteria
    @criteria = criteria.order_by(values)
    apply_option(:sort)
    self
  end
end

#take(limit = nil) ⇒ Document | Array<Document>

Take the given number of documents from the database.

Examples:

Take 10 documents

context.take(10)

Parameters:

  • limit (Integer | nil) (defaults to: nil)

    The number of documents to return or nil.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 374

def take(limit = nil)
  if limit
    limit(limit).to_a
  else
    # Do to_a first so that the Mongo#first method is not used and the
    # result is not sorted.
    limit(1).to_a.first
  end
end

#take!Document

Take one document from the database and raise an error if there are none.

Examples:

Take a document

context.take!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 393

def take!
  # Do to_a first so that the Mongo#first method is not used and the
  # result is not sorted.
  if fst = limit(1).to_a.first
    fst
  else
    raise Errors::DocumentNotFound.new(klass, nil, nil)
  end
end

#tally(field) ⇒ Hash

Get a hash of counts for the values of a single field. For example, if the following documents were in the database:

{ _id: 1, age: 21 }
{ _id: 2, age: 21 }
{ _id: 3, age: 22 }

Model.tally("age")

would yield the following result:

{ 21 => 2, 22 => 1 }

When tallying a field inside an array or embeds_many association:

{ _id: 1, array: [ { x: 1 }, { x: 2 } ] }
{ _id: 2, array: [ { x: 1 }, { x: 2 } ] }
{ _id: 3, array: [ { x: 1 }, { x: 3 } ] }

Model.tally("array.x")

The keys of the resulting hash are arrays:

{ [ 1, 2 ] => 2, [ 1, 3 ] => 1 }

Note that if tallying an element in an array of hashes, and the key doesn’t exist in some of the hashes, tally will not include those nil keys in the resulting hash:

{ _id: 1, array: [ { x: 1 }, { x: 2 }, { y: 3 } ] }

Model.tally("array.x")
# => { [ 1, 2 ] => 1 }

Parameters:

Returns:

  • (Hash)

    The hash of counts.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 440

def tally(field)
  name = klass.cleanse_localized_field_names(field)

  fld = klass.traverse_association_tree(name)
  pipeline = [ { "$group" => { _id: "$#{name}", counts: { "$sum": 1 } } } ]
  pipeline.unshift("$match" => view.filter) unless view.filter.blank?

  collection.aggregate(pipeline).reduce({}) do |tallies, doc|
    is_translation = "#{name}_translations" == field.to_s
    val = doc["_id"]

    key = if val.is_a?(Array)
      val.map do |v|
        demongoize_with_field(fld, v, is_translation)
      end
    else
      demongoize_with_field(fld, val, is_translation)
    end

    # The only time where a key will already exist in the tallies hash
    # is when the values are stored differently in the database, but
    # demongoize to the same value. A good example of when this happens
    # is when using localized fields. While the server query won't group
    # together hashes that have other values in different languages, the
    # demongoized value is just the translation in the current locale,
    # which can be the same across multiple of those unequal hashes.
    tallies[key] ||= 0
    tallies[key] += doc["counts"]
    tallies
  end
end

#thirdDocument | nil

Get the third document in the database for the criteria’s selector.

Examples:

Get the third document.

context.third

Returns:

  • (Document | nil)

    The third document or nil if none is found.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 651

def third
  retrieve_nth(2)
end

#third!Document

Get the third document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the third document.

context.third!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 665

def third!
  third || raise_document_not_found_error
end

#third_to_lastDocument | nil

Get the third to last document in the database for the criteria’s selector.

is found.

Examples:

Get the third to last document.

context.third_to_last

Returns:

  • (Document | nil)

    The third to last document or nil if none

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 751

def third_to_last
  retrieve_nth_to_last(2)
end

#third_to_last!Document

Get the third to last document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the third to last document.

context.third_to_last!

Returns:

  • (Document)

    The third to last document.

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 765

def third_to_last!
  third_to_last || raise_document_not_found_error
end

#update(attributes = nil, opts = {}) ⇒ nil | false

Update the first matching document atomically.

Examples:

Update the first matching document.

context.update({ "$set" => { name: "Smiths" }})

Parameters:

  • attributes (Hash) (defaults to: nil)

    The new attributes for the document.

  • opts (Hash) (defaults to: {})

    The update operation options.

Options Hash (opts):

  • :array_filters (Array)

    A set of filters specifying to which array elements an update should apply.

Returns:

  • (nil | false)

    False if no attributes were provided.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 516

def update(attributes = nil, opts = {})
  update_documents(attributes, :update_one, opts)
end

#update_all(attributes = nil, opts = {}) ⇒ nil | false

Update all the matching documents atomically.

Examples:

Update all the matching documents.

context.update_all({ "$set" => { name: "Smiths" }})

Parameters:

  • attributes (Hash) (defaults to: nil)

    The new attributes for each document.

  • opts (Hash) (defaults to: {})

    The update operation options.

Options Hash (opts):

  • :array_filters (Array)

    A set of filters specifying to which array elements an update should apply.

Returns:

  • (nil | false)

    False if no attributes were provided.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 532

def update_all(attributes = nil, opts = {})
  update_documents(attributes, :update_many, opts)
end

#update_documents(attributes, method = :update_one, opts = {}) ⇒ true | false (private)

This method is for internal use only.

Update the documents for the provided method.

Examples:

Update the documents.

context.update_documents(attrs)

Parameters:

  • attributes (Hash)

    The updates.

  • method (Symbol) (defaults to: :update_one)

    The method to use.

Returns:

  • (true | false)

    If the update succeeded.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 793

def update_documents(attributes, method = :update_one, opts = {})
  return false unless attributes

  view.send(method, AtomicUpdatePreparer.prepare(attributes, klass), opts)
end

#valid_for_count_documents?(hash = view.filter) ⇒ true | false (private)

Queries whether the current context is valid for use with the #count_documents? predicate. A context is valid if it does not include a ‘$where` operator.

TODO: Remove this method when we remove the deprecated for_js API. jira.mongodb.org/browse/MONGOID-5681

Returns:

  • (true | false)

    whether or not the current context excludes a ‘$where` operator.

[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 1032

def valid_for_count_documents?(hash = view.filter)
  # Note that `view.filter` is a BSON::Document, and all keys in a
  # BSON::Document are strings; we don't need to worry about symbol
  # representations of `$where`.
  hash.keys.each do |key|
    return false if key == '$where'
    return false if hash[key].is_a?(Hash) && !valid_for_count_documents?(hash[key])
  end

  true
end

#yield_document(document) {|doc| ... } (private)

This method is for internal use only.

Yield to the document.

Examples:

Yield the document.

context.yield_document(doc) do |doc|
  ...
end

Parameters:

  • document (Document)

    The document to yield to.

Yields:

  • (doc)
[ GitHub ]

  
# File 'lib/mongoid/contextual/mongo.rb', line 882

def yield_document(document, &block)
  doc = document.respond_to?(:_id) ?
      document : Factory.from_db(klass, document, criteria)
  yield(doc)
end