Class: Mongoid::Criteria

Inherits:
Object show all
Includes:
Enumerable
Defined in:
lib/mongoid/criteria.rb

Overview

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.

Example setup:

criteria = Criteria.new

criteria.only(:field).where(:field => "value").skip(20).limit(20)

criteria.execute

Constant Summary collapse

AGGREGATE_REDUCE =
"function(obj, prev) { prev.count++; }"
GROUP_REDUCE =
"function(obj, prev) { prev.group.push(obj); }"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass) ⇒ Criteria

Create the new Criteria object. This will initialize the selector and options hashes, as well as the type of criteria.

Options:

type: One of :all, :first:, or :last klass: The class to execute on.



216
217
218
# File 'lib/mongoid/criteria.rb', line 216

def initialize(klass)
  @selector, @options, @klass = { :_type => { "$in" => klass._types } }, {}, klass
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

Used for chaining Criteria scopes together in the for of class methods on the Document the criteria is for.

Options:

name: The name of the class method on the Document to chain. args: The arguments passed to the method.

Example:

class Person < Mongoid::Document
  field :title
  field :terms, :type => Boolean, :default => false

  class << self
    def knights
      all(:conditions => { :title => "Sir" })
    end

    def accepted
      all(:conditions => { :terms => true })
    end
  end
end

Person.accepted.knights #returns a merged criteria of the 2 scopes.

Returns: Criteria



297
298
299
300
301
302
303
304
305
# File 'lib/mongoid/criteria.rb', line 297

def method_missing(name, *args)
  if @klass.respond_to?(name)
    new_scope = @klass.send(name)
    new_scope.merge(self)
    return new_scope
  else
    return collect.send(name, *args)
  end
end

Instance Attribute Details

#klassObject (readonly)

Returns the value of attribute klass.



20
21
22
# File 'lib/mongoid/criteria.rb', line 20

def klass
  @klass
end

#optionsObject (readonly)

Returns the value of attribute options.



20
21
22
# File 'lib/mongoid/criteria.rb', line 20

def options
  @options
end

#selectorObject (readonly)

Returns the value of attribute selector.



20
21
22
# File 'lib/mongoid/criteria.rb', line 20

def selector
  @selector
end

Class Method Details

.translate(*args) ⇒ Object

Translate the supplied arguments into a Criteria object.

If the passed in args is a single String, then it will construct an id Criteria from it.

If the passed in args are a type and a hash, then it will construct the Criteria with the proper selector, options, and type.

Options:

args: either a String or a Symbol, +Hash combination.

Example:

Criteria.translate(Person, "4ab2bc4b8ad548971900005c")

Criteria.translate(Person, :conditions => { :field => "value"}, :limit => 20)

Returns a new Criteria object.



440
441
442
443
444
445
446
447
448
449
450
451
# File 'lib/mongoid/criteria.rb', line 440

def self.translate(*args)
  klass = args[0]
  params = args[1] || {}
  if params.is_a?(String)
    document = new(klass).id(params).one
    if Mongoid.raise_not_found_error
      raise Errors::DocumentNotFound.new(klass, params) unless document
    end
    return document
  end
  return new(klass).where(params.delete(:conditions) || {}).extras(params)
end

Instance Method Details

#==(other) ⇒ Object

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

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

Options:

other: The other Enumerable or Criteria to compare to.



30
31
32
33
34
35
36
37
38
39
40
# File 'lib/mongoid/criteria.rb', line 30

def ==(other)
  case other
  when Criteria
    self.selector == other.selector && self.options == other.options
  when Enumerable
    @collection ||= execute
    return (@collection == other)
  else
    return false
  end
end

#aggregate(klass = nil) ⇒ Object

Aggregate the criteria. This will take the internally built selector and options and pass them on to the Ruby driver’s group() method on the collection. The collection itself will be retrieved from the class provided, and once the query has returned it will provided a grouping of keys with counts.

Example:

criteria.select(:field1).where(:field1 => "Title").aggregate(Person)



51
52
53
54
# File 'lib/mongoid/criteria.rb', line 51

def aggregate(klass = nil)
  @klass = klass if klass
  @klass.collection.group(@options[:fields], @selector, { :count => 0 }, AGGREGATE_REDUCE)
end

#all(attributes = {}) ⇒ Object

Adds a criterion to the Criteria that specifies values that must all be matched in order to return results. Similar to an “in” clause but the underlying conditional logic is an “AND” and not an “OR”. The MongoDB conditional operator that will be used is “$all”.

Options:

attributes: A Hash where the key is the field name and the value is an Array of values that must all match.

Example:

criteria.all(:field => ["value1", "value2"])

criteria.all(:field1 => ["value1", "value2"], :field2 => ["value1"])

Returns: self



73
74
75
# File 'lib/mongoid/criteria.rb', line 73

def all(attributes = {})
  update_selector(attributes, "$all")
end

#and(selector = nil) ⇒ Object

Adds a criterion to the Criteria that specifies values that must be matched in order to return results. This is similar to a SQL “WHERE” clause. This is the actual selector that will be provided to MongoDB, similar to the Javascript object that is used when performing a find() in the MongoDB console.

Options:

selectior: A Hash that must match the attributes of the Document.

Example:

criteria.and(:field1 => "value1", :field2 => 15)

Returns: self



92
93
94
# File 'lib/mongoid/criteria.rb', line 92

def and(selector = nil)
  where(selector)
end

#countObject

Get the count of matching documents in the database for the Criteria.

Example:

criteria.count

Returns: Integer



103
104
105
# File 'lib/mongoid/criteria.rb', line 103

def count
  @count ||= @klass.collection.find(@selector, @options.dup).count
end

#each(&block) ⇒ Object

Iterate over each Document in the results. This can take an optional block to pass to each argument in the results.

Example:

criteria.each { |doc| p doc }



113
114
115
116
# File 'lib/mongoid/criteria.rb', line 113

def each(&block)
  @collection ||= execute
  block_given? ? @collection.each { |doc| yield doc } : self
end

#excludes(attributes = {}) ⇒ Object

Adds a criterion to the Criteria that specifies values that are not allowed to match any document in the database. The MongoDB conditional operator that will be used is “$ne”.

Options:

attributes: A Hash where the key is the field name and the value is a value that must not be equal to the corresponding field value in the database.

Example:

criteria.excludes(:field => "value1")

criteria.excludes(:field1 => "value1", :field2 => "value1")

Returns: self



134
135
136
# File 'lib/mongoid/criteria.rb', line 134

def excludes(attributes = {})
  update_selector(attributes, "$ne")
end

#extras(extras) ⇒ Object

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

Options:

extras: A Hash that gets set to the driver options.

Example:

criteria.extras(:limit => 20, :skip => 40)

Returns: self



150
151
152
# File 'lib/mongoid/criteria.rb', line 150

def extras(extras)
  @options = extras; filter_options; self
end

#groupObject

Groups the criteria. This will take the internally built selector and options and pass them on to the Ruby driver’s group() method on the collection. The collection itself will be retrieved from the class provided, and once the query has returned it will provided a grouping of keys with objects.

Example:

criteria.select(:field1).where(:field1 => "Title").group(Person)



163
164
165
166
167
168
169
170
171
172
# File 'lib/mongoid/criteria.rb', line 163

def group
  @klass.collection.group(
    @options[:fields],
    @selector,
    { :group => [] },
    GROUP_REDUCE
  ).collect do |docs|
    docs["group"] = docs["group"].collect { |attrs| @klass.instantiate(attrs) }; docs
  end
end

#id(object_id) ⇒ Object

Adds a criterion to the Criteria that specifies an id that must be matched.

Options:

object_id: A String representation of a Mongo::ObjectID

Example:

criteria.id("4ab2bc4b8ad548971900005c")

Returns: self



205
206
207
# File 'lib/mongoid/criteria.rb', line 205

def id(object_id)
  @selector[:_id] = object_id; self
end

#in(attributes = {}) ⇒ Object

Adds a criterion to the Criteria that specifies values where any can be matched in order to return results. This is similar to an SQL “IN” clause. The MongoDB conditional operator that will be used is “$in”.

Options:

attributes: A Hash where the key is the field name and the value is an Array of values that any can match.

Example:

criteria.in(:field => ["value1", "value2"])

criteria.in(:field1 => ["value1", "value2"], :field2 => ["value1"])

Returns: self



190
191
192
# File 'lib/mongoid/criteria.rb', line 190

def in(attributes = {})
  update_selector(attributes, "$in")
end

#lastObject

Return the last result for the Criteria. Essentially does a find_one on the collection with the sorting reversed. If no sorting parameters have been provided it will default to ids.

Example:

Criteria.select(:name).where(:name = "Chrissy").last



227
228
229
230
231
232
233
234
# File 'lib/mongoid/criteria.rb', line 227

def last
  opts = @options.dup
  sorting = opts[:sort]
  sorting = [[:_id, :asc]] unless sorting
  opts[:sort] = sorting.collect { |option| [ option[0], option[1].invert ] }
  attributes = @klass.collection.find_one(@selector, opts)
  attributes ? @klass.instantiate(attributes) : nil
end

#limit(value = 20) ⇒ Object

Adds a criterion to the Criteria that specifies the maximum number of results to return. This is mostly used in conjunction with skip() to handle paginated results.

Options:

value: An Integer specifying the max number of results. Defaults to 20.

Example:

criteria.limit(100)

Returns: self



249
250
251
# File 'lib/mongoid/criteria.rb', line 249

def limit(value = 20)
  @options[:limit] = value; self
end

#merge(other) ⇒ Object

Merges another object into this 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.

Options:

other: The Criteria or Hash to merge with.

Example:

criteria.merge({ :conditions => { :title => "Sir" } })



264
265
266
267
# File 'lib/mongoid/criteria.rb', line 264

def merge(other)
  @selector.update(other.selector)
  @options.update(other.options)
end

#not_in(exclusions) ⇒ Object

Adds a criterion to the Criteria that specifies values where none should match in order to return results. This is similar to an SQL “NOT IN” clause. The MongoDB conditional operator that will be used is “$nin”.

Options:

exclusions: A Hash where the key is the field name and the value is an Array of values that none can match.

Example:

criteria.not_in(:field => ["value1", "value2"])

criteria.not_in(:field1 => ["value1", "value2"], :field2 => ["value1"])

Returns: self



323
324
325
# File 'lib/mongoid/criteria.rb', line 323

def not_in(exclusions)
  exclusions.each { |key, value| @selector[key] = { "$nin" => value } }; self
end

#offsetObject

Returns the offset option. If a per_page option is in the list then it will replace it with a skip parameter and return the same value. Defaults to 20 if nothing was provided.



330
331
332
# File 'lib/mongoid/criteria.rb', line 330

def offset
  @options[:skip]
end

#oneObject Also known as: first

Return the first result for the Criteria.

Example:

Criteria.select(:name).where(:name = "Chrissy").one



339
340
341
342
# File 'lib/mongoid/criteria.rb', line 339

def one
  attributes = @klass.collection.find_one(@selector, @options.dup)
  attributes ? @klass.instantiate(attributes) : nil
end

#only(*args) ⇒ Object

Adds a criterion to the Criteria that specifies the fields that will get returned from the Document. Used mainly for list views that do not require all fields to be present. This is similar to SQL “SELECT” values.

Options:

args: A list of field names to retrict the returned fields to.

Example:

criteria.only(:field1, :field2, :field3)

Returns: self



359
360
361
# File 'lib/mongoid/criteria.rb', line 359

def only(*args)
  @options[:fields] = args.flatten if args.any?; self
end

#order_by(params = []) ⇒ Object

Adds a criterion to the Criteria that specifies the sort order of the returned documents in the database. Similar to a SQL “ORDER BY”.

Options:

params: An Array of [field, direction] sorting pairs.

Example:

criteria.order_by([[:field1, :asc], [:field2, :desc]])

Returns: self



375
376
377
# File 'lib/mongoid/criteria.rb', line 375

def order_by(params = [])
  @options[:sort] = params; self
end

#pageObject

Either returns the page option and removes it from the options, or returns a default value of 1.



381
382
383
384
# File 'lib/mongoid/criteria.rb', line 381

def page
  skips, limits = @options[:skip], @options[:limit]
  (skips && limits) ? (skips + limits) / limits : 1
end

#paginateObject

Executes the Criteria and paginates the results.

Example:

criteria.paginate



391
392
393
394
395
396
# File 'lib/mongoid/criteria.rb', line 391

def paginate
  @collection ||= execute
  WillPaginate::Collection.create(page, per_page, count) do |pager|
    pager.replace(@collection)
  end
end

#per_pageObject

Returns the number of results per page or the default of 20.



399
400
401
# File 'lib/mongoid/criteria.rb', line 399

def per_page
  (@options[:limit] || 20).to_i
end

#skip(value = 0) ⇒ Object

Adds a criterion to the Criteria that specifies how many results to skip when returning Documents. This is mostly used in conjunction with limit() to handle paginated results, and is similar to the traditional “offset” parameter.

Options:

value: An Integer specifying the number of results to skip. Defaults to 0.

Example:

criteria.skip(20)

Returns: self



417
418
419
# File 'lib/mongoid/criteria.rb', line 417

def skip(value = 0)
  @options[:skip] = value; self
end

#where(selector = nil) ⇒ Object

Adds a criterion to the Criteria that specifies values that must be matched in order to return results. This is similar to a SQL “WHERE” clause. This is the actual selector that will be provided to MongoDB, similar to the Javascript object that is used when performing a find() in the MongoDB console.

Options:

selectior: A Hash that must match the attributes of the Document.

Example:

criteria.where(:field1 => "value1", :field2 => 15)

Returns: self



468
469
470
471
472
473
474
475
476
# File 'lib/mongoid/criteria.rb', line 468

def where(selector = nil)
  case selector
  when String
    @selector.update("$where" => selector)
  else
    @selector.update(selector ? selector.expand_complex_criteria : {})
  end
  self
end