scopes
Similar to Active Record, Mongoid allows you to define scopes on your models as a convenience for filtering result sets. Scopes are defined at the class level, either using the scope macro or by defining class methods that return a criteria object. All scopes are chainable and can be applied to associations as well, the later being discussed in the relations section.
named scopes
Named scopes are defined at the class level using a scope macro and can be chained to create result sets in a nice DSL.
class Person include Mongoid::Document field :occupation, type: String field :age, type: Integer scope :rock_n_rolla, where(occupation: "Rockstar") scope :washed_up, where(:age.gt => 30) scope :over, ->(limit) { where(:age.gt => limit) } end # Find all the rockstars. Person.rock_n_rolla # Find all rockstars that should probably quit. Person.washed_up.rock_n_rolla # Find a criteria with Keith Richards in it. Person.rock_n_rolla.over(60)
Note that definitions are evaluated at class load time. For evaluation at runtime you will want to make sure to define using a proc or lambda. In the following example the first date is set as the date of class load, where the second scope sets the date at the time the scope is called.
scope :current, where(:start_date.lte => Date.today) scope :current, -> { where(:start_date.lte => Date.today) }
class methods
For those who prefer a Data Mapper style syntax, class methods that return criteria can be treated as chainable scopes as well.
class Person include Mongoid::Document field :occupation, type: String field :age, type: Integer class << self def rock_n_rolla where(occupation: "Rockstar") end def washed_up where(:age.gt => 30) end def over(limit) where(:age.gt => limit) end end end # Find all the rockstars. Person.rock_n_rolla # Find all rockstars that should probably quit. Person.washed_up.rock_n_rolla # Find a criteria with Keith Richards in it. Person.rock_n_rolla.over(60)
Named scopes and class methods that return a criteria can be chained together - that's the beauty of Mongoid's powerful criteria API.
class Person include Mongoid::Document field :occupation, type: String field :age, type: Integer scope :washed_up, where(:age.gt => 30) scope :over, ->(limit) { where(:age.gt => limit) } def self.rock_n_rolla where(occupation: "Rockstar") end end # Same queries apply here as well. Person.rock_n_rolla Person.washed_up.rock_n_rolla Person.rock_n_rolla.over(60)
default scopes
You can supply a default scope at the class level to tell Mongoid that all queries need to filter by the provided criteria without needing to specify it for every query. This is very useful when you find yourself filtering by a particular criterion many times througout an application.
class Person include Mongoid::Document field :occupation, type: String field :age, type: Integer default_scope where(occupation: "Rockstar") scope :washed_up, where(:age.gt => 30) end # We seem to search for rockstars all the time, so just make that # included by default. The following query applies the rock_n_rolla # scope to it by default. Person.washed_up
When a default scope is defined, you may find yourself executing queries that do not need the default applied. This is where Mongoid's familiar unscoped method comes in.
# We just want some old people who aren't rockstars. Person.unscoped.washed_up