Class: MongoDoc::Criteria

Inherits:
Object show all
Includes:
Enumerable
Defined in:
lib/mongodoc/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.select(:field => "value").only(:field).skip(20).limit(20)

criteria.execute

Constant Summary collapse

SORT_REVERSALS =
{
  :asc => :desc,
  :ascending => :descending,
  :desc => :asc,
  :descending => :ascending
}
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.



219
220
221
# File 'lib/mongodoc/criteria.rb', line 219

def initialize(klass)
  @selector, @options, @klass = {}, {}, 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



299
300
301
302
303
# File 'lib/mongodoc/criteria.rb', line 299

def method_missing(name, *args)
  new_scope = klass.send(name)
  new_scope.merge(self)
  new_scope
end

Instance Attribute Details

#klassObject (readonly)

Returns the value of attribute klass.



28
29
30
# File 'lib/mongodoc/criteria.rb', line 28

def klass
  @klass
end

#optionsObject (readonly)

Returns the value of attribute options.



28
29
30
# File 'lib/mongodoc/criteria.rb', line 28

def options
  @options
end

#selectorObject (readonly)

Returns the value of attribute selector.



28
29
30
# File 'lib/mongodoc/criteria.rb', line 28

def selector
  @selector
end

Class Method Details

.translate(klass, params = {}) ⇒ 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.



429
430
431
432
# File 'lib/mongodoc/criteria.rb', line 429

def self.translate(klass, params = {})
  return new(klass).id(params).one if params.is_a?(String)
  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.



38
39
40
41
42
43
44
45
46
47
48
# File 'lib/mongodoc/criteria.rb', line 38

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(use_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)



59
60
61
62
# File 'lib/mongodoc/criteria.rb', line 59

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

#countObject

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

Example:

criteria.count

Returns: Integer



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

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

#each(&block) ⇒ Object

Iterate over each Document in the results and pass each document to the block.

Example:

criteria.each { |doc| p doc }



102
103
104
105
106
107
108
109
# File 'lib/mongodoc/criteria.rb', line 102

def each(&block)
  @collection ||= execute
  if block_given?
    @collection.each(&block)
  else
    self
  end
end

#every(selections = {}) ⇒ 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:

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

Example:

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

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

Returns: self



81
82
83
# File 'lib/mongodoc/criteria.rb', line 81

def every(selections = {})
  selections.each { |key, value| selector[key] = { "$all" => value } }; self
end

#excludes(exclusions = {}) ⇒ 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:

excludes: 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



127
128
129
# File 'lib/mongodoc/criteria.rb', line 127

def excludes(exclusions = {})
  exclusions.each { |key, value| selector[key] = { "$ne" => value } }; self
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



143
144
145
146
147
# File 'lib/mongodoc/criteria.rb', line 143

def extras(extras)
  options.merge!(extras)
  filter_options
  self
end

#group(use_klass = nil) ⇒ Object

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)



168
169
170
171
172
173
174
175
# File 'lib/mongodoc/criteria.rb', line 168

def group(use_klass = nil)
  (use_klass || klass).collection.group(
    options[:fields],
    selector,
    { :group => [] },
    GROUP_REDUCE
  ).collect {|docs| docs["group"] = MongoDoc::BSON.decode(docs["group"]); docs }
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



208
209
210
# File 'lib/mongodoc/criteria.rb', line 208

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

#in(inclusions = {}) ⇒ 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:

inclusions: 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



193
194
195
# File 'lib/mongodoc/criteria.rb', line 193

def in(inclusions = {})
  inclusions.each { |key, value| selector[key] = { "$in" => value } }; self
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



230
231
232
233
234
235
236
# File 'lib/mongodoc/criteria.rb', line 230

def last
  opts = options.dup
  sorting = opts[:sort]
  sorting = [[:_id, :asc]] unless sorting
  opts[:sort] = sorting.collect { |option| [ option.first, Criteria.invert(option.last) ] }
  klass.collection.find_one(selector, opts)
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



251
252
253
# File 'lib/mongodoc/criteria.rb', line 251

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" } })



266
267
268
269
# File 'lib/mongodoc/criteria.rb', line 266

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



321
322
323
# File 'lib/mongodoc/criteria.rb', line 321

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.



328
329
330
# File 'lib/mongodoc/criteria.rb', line 328

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



154
155
156
# File 'lib/mongodoc/criteria.rb', line 154

def one
  klass.collection.find_one(selector, options.dup)
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



344
345
346
# File 'lib/mongodoc/criteria.rb', line 344

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.



350
351
352
353
354
355
356
# File 'lib/mongodoc/criteria.rb', line 350

def page
  if options[:skip] && options[:limit]
    (options[:skip].to_i + options[:limit].to_i) / options[:limit].to_i
  else
    1
  end
end

#paginateObject

Executes the Criteria and paginates the results.

Example:

criteria.paginate



363
364
365
366
367
368
# File 'lib/mongodoc/criteria.rb', line 363

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

#per_pageObject

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



371
372
373
# File 'lib/mongodoc/criteria.rb', line 371

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

#select(*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.select(:field1, :field2, :field3)

Returns: self



388
389
390
# File 'lib/mongodoc/criteria.rb', line 388

def select(*args)
  options[:fields] = args.flatten if args.any?; self
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



406
407
408
# File 'lib/mongodoc/criteria.rb', line 406

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

#where(add_selector = {}) ⇒ 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



449
450
451
# File 'lib/mongodoc/criteria.rb', line 449

def where(add_selector = {})
  selector.merge!(add_selector); self
end