class Mongoid::Criteria

The Criteria class is the core object needed in Mongoid to retrieve objects from the database. It is a DSL that essentially sets up the selector and options arguments that get passed on to a Mongo::Collection in the Ruby driver. Each method on the Criteria returns self to they can be chained in order to create a readable criterion to be executed against the database.

Constants

CHECK

Static array used to check with method missing - we only need to ever instantiate once.

Attributes

association[RW]
embedded[RW]
klass[RW]
parent_document[RW]

Public Class Methods

from_hash(hash) click to toggle source

Convert the given hash to a criteria. Will iterate over each keys in the hash which must correspond to method on a criteria object. The hash must also include a “klass” key.

@example Convert the hash to a criteria.

Criteria.from_hash({ klass: Band, where: { name: "Depeche Mode" })

@param [ Hash ] hash The hash to convert.

@return [ Criteria ] The criteria.

# File lib/mongoid/criteria.rb, line 55
def from_hash(hash)
  criteria = Criteria.new(hash.delete(:klass) || hash.delete('klass'))
  hash.each_pair do |method, args|
    criteria = criteria.__send__(method, args)
  end
  criteria
end
new(klass) click to toggle source

Initialize the new criteria.

@example Init the new criteria.

Criteria.new(Band)

@param [ Class ] klass The model class.

Calls superclass method Mongoid::Criteria::Modifiable#new
# File lib/mongoid/criteria.rb, line 233
def initialize(klass)
  @klass = klass
  @embedded = nil
  @none = nil
  klass ? super(klass.aliased_fields, klass.fields, klass.relations, klass.aliased_associations) : super({}, {}, {}, {})
end

Public Instance Methods

==(other) click to toggle source

Returns true if the supplied Enumerable or Criteria is equal to the results of this Criteria or the criteria itself.

@note This will force a database load when called if an enumerable is passed.

@param [ Object ] other The other Enumerable or Criteria to compare to.

@return [ true | false ] If the objects are equal.

Calls superclass method Mongoid::Criteria::Queryable#==
# File lib/mongoid/criteria.rb, line 78
def ==(other)
  return super if other.respond_to?(:selector)
  entries == other
end
_enumerable_find(*args, &block)

@api private

Alias for: find
_findable_find(*args, &block)

@api private

Alias for: find
as_json(options = nil) click to toggle source

Needed to properly get a criteria back as json

@example Get the criteria as json.

Person.where(:title => "Sir").as_json

@param [ Hash ] options Options to pass through to the serializer.

@return [ String ] The JSON string.

# File lib/mongoid/criteria.rb, line 140
def as_json(options = nil)
  entries.as_json(options)
end
documents() click to toggle source

Get the documents from the embedded criteria.

@example Get the documents.

criteria.documents

@return [ Array<Document> ] The documents.

# File lib/mongoid/criteria.rb, line 150
def documents
  @documents ||= []
end
documents=(docs) click to toggle source

Set the embedded documents on the criteria.

@example Set the documents.

@param [ Array<Document> ] docs The embedded documents.

@return [ Array<Document> ] The embedded documents.

# File lib/mongoid/criteria.rb, line 161
def documents=(docs)
  @documents = docs
end
embedded?() click to toggle source

Is the criteria for embedded documents?

@example Is the criteria for embedded documents?

criteria.embedded?

@return [ true | false ] If the criteria is embedded.

# File lib/mongoid/criteria.rb, line 171
def embedded?
  !!@embedded
end
empty_and_chainable?() click to toggle source

Is the criteria an empty but chainable criteria?

@example Is the criteria a none criteria?

criteria.empty_and_chainable?

@return [ true | false ] If the criteria is a none.

# File lib/mongoid/criteria.rb, line 301
def empty_and_chainable?
  !!@none
end
extract_id() click to toggle source

Extract a single id from the provided criteria. Could be in an $and query or a straight _id query.

@example Extract the id.

criteria.extract_id

@return [ Object ] The id.

# File lib/mongoid/criteria.rb, line 182
def extract_id
  selector['_id'] || selector[:_id] || selector['id'] || selector[:id]
end
extras(extras) click to toggle source

Adds a criterion to the Criteria that specifies additional options to be passed to the Ruby driver, in the exact format for the driver.

@example Add extra params to the criteria. criteria.extras(:limit => 20, :skip => 40)

@param [ Hash ] extras The extra driver options.

@return [ Criteria ] The cloned criteria.

# File lib/mongoid/criteria.rb, line 195
def extras(extras)
  crit = clone
  crit.options.merge!(extras)
  crit
end
field_list() click to toggle source

Get the list of included fields.

@example Get the field list.

criteria.field_list

@return [ Array<String> ] The fields.

# File lib/mongoid/criteria.rb, line 207
def field_list
  if options[:fields]
    options[:fields].keys.reject{ |key| key == klass.discriminator_key }
  else
    []
  end
end
find(*args, &block) click to toggle source

Finds one or many documents given the provided _id values, or filters the documents in the current scope in the application process space after loading them if needed.

If this method is not given a block, it delegates to +Findable#find+ and finds one or many documents for the provided _id values.

If this method is given a block, it delegates to +Enumerable#find+ and returns the first document of those found by the current Crieria object for which the block returns a truthy value.

Note that the “default proc” argument of Enumerable is not specially treated by Mongoid - the decision between delegating to Findable vs Enumerable is made solely based on whether find is passed a block.

@note Each argument can be an individual id, an array of ids or

a nested array. Each array will be flattened.

@example Finds a document by its _id, invokes Findable#find.

critera.find("1234")

@example Finds the first matching document using a block, invokes Enumerable#find.

criteria.find { |item| item.name == "Depeche Mode" }

@example Finds the first matching document using a block using the default Proc, invokes Enumerable#find.

criteria.find(-> { "Default Band" }) { |item| item.name == "Milwaukee Mode" }

@example Tries to find a document whose _id is the stringification of the provided Proc, typically failing.

enumerator = criteria.find(-> { "Default Band" })

@param [ [ Object | Array<Object> ]… ] *args The id(s). @param &block Optional block to pass. @yield [ Object ] Yields each enumerable element to the block.

@return [ Document | Array<Document> | nil ] A document or matching documents.

@raise Errors::DocumentNotFound If the parameters were _id values and

not all documents are found and the +raise_not_found_error+
Mongoid configuration option is truthy.

@see ruby-doc.org/core/Enumerable.html#method-i-find

# File lib/mongoid/criteria.rb, line 124
def find(*args, &block)
  if block_given?
    _enumerable_find(*args, &block)
  else
    _findable_find(*args)
  end
end
Also aliased as: _enumerable_find, _findable_find
for_js(javascript, scope = {}) click to toggle source

Find documents by the provided javascript and scope. Uses a $where but is different from +Criteria#where+ in that it will pass a code object to the query instead of a pure string. Safe against Javascript injection attacks.

@example Find by javascript.

Band.for_js("this.name = param", param: "Tool")

@param [ String ] javascript The javascript to execute in the $where. @param [ Hash ] scope The scope for the code.

@return [ Criteria ] The criteria.

@deprecated

# File lib/mongoid/criteria.rb, line 466
def for_js(javascript, scope = {})
  code = if scope.empty?
    # CodeWithScope is not supported for $where as of MongoDB 4.4
    BSON::Code.new(javascript)
  else
    BSON::CodeWithScope.new(javascript, scope)
  end
  js_query(code)
end
freeze() click to toggle source

When freezing a criteria we need to initialize the context first otherwise the setting of the context on attempted iteration will raise a runtime error.

@example Freeze the criteria.

criteria.freeze

@return [ Criteria ] The frozen criteria.

Calls superclass method
# File lib/mongoid/criteria.rb, line 223
def freeze
  context and inclusions and super
end
merge(other) click to toggle source

Merges another object with this Criteria and returns a new criteria. The other object may be a Criteria or a Hash. This is used to combine multiple scopes together, where a chained scope situation may be desired.

@example Merge the criteria with another criteria.

criteria.merge(other_criteria)

@example Merge the criteria with a hash. The hash must contain a klass

key and the key/value pairs correspond to method names/args.

criteria.merge({
  klass: Band,
  where: { name: "Depeche Mode" },
  order_by: { name: 1 }
})

@param [ Criteria ] other The other criterion to merge with.

@return [ Criteria ] A cloned self.

# File lib/mongoid/criteria.rb, line 260
def merge(other)
  crit = clone
  crit.merge!(other)
  crit
end
merge!(other) click to toggle source

Merge the other criteria into this one.

@example Merge another criteria into this criteria.

criteria.merge(Person.where(name: "bob"))

@param [ Criteria | Hash ] other The criteria to merge in.

@return [ Criteria ] The merged criteria.

# File lib/mongoid/criteria.rb, line 274
def merge!(other)
  other = self.class.from_hash(other) if other.is_a?(Hash)
  selector.merge!(other.selector)
  options.merge!(other.options)
  self.documents = other.documents.dup unless other.documents.empty?
  self.scoping_options = other.scoping_options
  self.inclusions = (inclusions + other.inclusions).uniq
  self
end
none() click to toggle source

Returns a criteria that will always contain zero results and never hits the database.

@example Return a none criteria.

criteria.none

@return [ Criteria ] The none criteria.

# File lib/mongoid/criteria.rb, line 291
def none
  @none = true and self
end
only(*args) click to toggle source

Overriden to include _type in the fields.

@example Limit the fields returned from the database.

Band.only(:name)

@param [ [ Symbol | Array<Symbol> ]… ] *args The field name(s).

@return [ Criteria ] The cloned criteria.

Calls superclass method
# File lib/mongoid/criteria.rb, line 313
def only(*args)
  args = args.flatten
  return clone if args.empty?
  if (args & Fields::IDS).empty?
    args.unshift(:_id)
  end
  if klass.hereditary?
    args.push(klass.discriminator_key.to_sym)
  end
  super(*args)
end
read(value = nil) click to toggle source

Set the read preference for the criteria.

@example Set the read preference.

criteria.read(mode: :primary_preferred)

@param [ Hash ] value The mode preference.

@return [ Criteria ] The cloned criteria.

# File lib/mongoid/criteria.rb, line 333
def read(value = nil)
  clone.tap do |criteria|
    criteria.options.merge!(read: value)
  end
end
respond_to?(name, include_private = false) click to toggle source

Returns true if criteria responds to the given method.

@example Does the criteria respond to the method?

crtiteria.respond_to?(:each)

@param [ Symbol ] name The name of the class method on the Document. @param [ true | false ] include_private Whether to include privates.

@return [ true | false ] If the criteria responds to the method.

Calls superclass method
# File lib/mongoid/criteria.rb, line 361
def respond_to?(name, include_private = false)
  super || klass.respond_to?(name) || CHECK.respond_to?(name, include_private)
end
to_criteria() click to toggle source

Convenience for objects that want to be merged into a criteria.

@example Convert to a criteria.

criteria.to_criteria

@return [ Criteria ] self. @deprecated

# File lib/mongoid/criteria.rb, line 374
def to_criteria
  self
end
to_proc() click to toggle source

Convert the criteria to a proc.

@example Convert the criteria to a proc.

criteria.to_proc

@return [ Proc ] The wrapped criteria.

# File lib/mongoid/criteria.rb, line 385
def to_proc
  ->{ self }
end
type(types) click to toggle source

Adds a criterion to the Criteria that specifies a type or an Array of types that must be matched.

@example Match only specific models.

criteria.type('Browser')
criteria.type(['Firefox', 'Browser'])

@param [ Array<String> ] types The types to match against.

@return [ Criteria ] The cloned criteria.

# File lib/mongoid/criteria.rb, line 399
def type(types)
  any_in(self.discriminator_key.to_sym => Array(types))
end
where(*args) click to toggle source

This is the general entry point for most MongoDB queries. This either creates a standard field: value selection, and expanded selection with the use of hash methods, or a $where selection if a string is provided.

@example Add a standard selection.

criteria.where(name: "syd")

@example Add a javascript selection.

criteria.where("this.name == 'syd'")

@param [ [ Hash | String ]… ] *args The standard selection

or javascript string.

@raise [ UnsupportedJavascript ] If provided a string and the criteria

is embedded.

@return [ Criteria ] The cloned selectable.

Calls superclass method
# File lib/mongoid/criteria.rb, line 420
def where(*args)
  # Historically this method required exactly one argument.
  # As of https://jira.mongodb.org/browse/MONGOID-4804 it also accepts
  # zero arguments.
  # The underlying where implemetation that super invokes supports
  # any number of arguments, but we don't presently allow mutiple
  # arguments through this method. This API can be reconsidered in the
  # future.
  if args.length > 1
    raise ArgumentError, "Criteria#where requires zero or one arguments (given #{args.length})"
  end
  if args.length == 1
    expression = args.first
    if expression.is_a?(::String) && embedded?
      raise Errors::UnsupportedJavascript.new(klass, expression)
    end
  end
  super
end
without(*args) click to toggle source

Overriden to exclude _id from the fields.

@example Exclude fields returned from the database.

Band.without(:name)

@param [ Symbol… ] *args The field name(s).

@return [ Criteria ] The cloned criteria.

Calls superclass method
# File lib/mongoid/criteria.rb, line 347
def without(*args)
  args -= id_fields
  super(*args)
end
without_options() click to toggle source

Get a version of this criteria without the options.

@example Get the criteria without options.

criteria.without_options

@return [ Criteria ] The cloned criteria.

# File lib/mongoid/criteria.rb, line 446
def without_options
  crit = clone
  crit.options.clear
  crit
end

Private Instance Methods

check_for_missing_documents!(result, ids) click to toggle source

Are documents in the query missing, and are we configured to raise an error?

@api private

@example Check for missing documents.

criteria.check_for_missing_documents!([], [ 1 ])

@param [ Array<Document> ] result The result. @param [ Array<Object> ] ids The ids.

@raise [ Errors::DocumentNotFound ] If none are found and raising an

error.
# File lib/mongoid/criteria.rb, line 492
def check_for_missing_documents!(result, ids)
  if (result.size < ids.size) && Mongoid.raise_not_found_error
    raise Errors::DocumentNotFound.new(klass, ids, ids - result.map(&:_id))
  end
end
initialize_copy(other) click to toggle source

Clone or dup the current Criteria. This will return a new criteria with the selector, options, klass, embedded options, etc intact.

@api private

@example Clone a criteria.

criteria.clone

@example Dup a criteria.

criteria.dup

@param [ Criteria ] other The criteria getting cloned.

@return [ nil ] nil.

# File lib/mongoid/criteria.rb, line 512
def initialize_copy(other)
  @inclusions = other.inclusions.dup
  @scoping_options = other.scoping_options
  @documents = other.documents.dup
  @context = nil
  super
end
merge_type_selection() click to toggle source

For models where inheritance is at play we need to add the type selection.

@example Add the type selection.

criteria.merge_type_selection

@return [ true | false ] If type selection was added.

# File lib/mongoid/criteria.rb, line 549
def merge_type_selection
  selector.merge!(type_selection) if type_selectable?
end
method_missing(name, *args, &block) click to toggle source
Calls superclass method
# File lib/mongoid/criteria.rb, line 530
               def method_missing(name, *args, &block)
  if klass.respond_to?(name)
    klass.send(:with_scope, self) do
      klass.send(name, *args, &block)
    end
  elsif CHECK.respond_to?(name)
    return entries.send(name, *args, &block)
  else
    super
  end
end
selector_with_type_selection() click to toggle source

Get a new selector with type selection in it.

@api private

@example Get a selector with type selection.

criteria.selector_with_type_selection

@return [ Hash ] The selector.

# File lib/mongoid/criteria.rb, line 592
def selector_with_type_selection
  type_selectable? ? selector.merge(type_selection) : selector
end
type_selectable?() click to toggle source

Is the criteria type selectable?

@api private

@example If the criteria type selectable?

criteria.type_selectable?

@return [ true | false ] If type selection should be added.

# File lib/mongoid/criteria.rb, line 561
def type_selectable?
  klass.hereditary? &&
    !selector.keys.include?(self.discriminator_key) &&
    !selector.keys.include?(self.discriminator_key.to_sym)
end
type_selection() click to toggle source

Get the selector for type selection.

@api private

@example Get a type selection hash.

criteria.type_selection

@return [ Hash ] The type selection.

# File lib/mongoid/criteria.rb, line 575
def type_selection
  klasses = klass._types
  if klasses.size > 1
    { klass.discriminator_key.to_sym => { "$in" => klass._types }}
  else
    { klass.discriminator_key.to_sym => klass._types[0] }
  end
end