Jump To …

queries.rb

Example of Queries with Mongo Model.

In this example we’ll see standard MongoDB queries, dynamic finders and scopes.

require 'mongo/model'

Connecting to test database and cleaning it before starting.

Mongo::Model.default_database_name = :default_test
Mongo::Model.default_database.clear

Defining Game Unit.

class Unit
  inherit Mongo::Model
  collection :units

  attr_accessor :name, :status, :race

  def inspect; name end
end

Populating database.

zeratul  = Unit.create name: 'Zeratul',  race: 'Protoss', status: 'alive'
tassadar = Unit.create name: 'Tassadar', race: 'Protoss', status: 'dead'
jim      = Unit.create name: 'Jim',      race: 'Terran',  status: 'alive'

Standard MongoDB queries (there’s also each method, the same as all).

p Unit.first(name: 'Zeratul')                        # => Zeratul
p Unit.all(name: 'Zeratul')                          # => [Zeratul]
Unit.all name: 'Zeratul' do |unit|
  p unit                                             # => Zeratul
end

Simple dynamic finders.

p Unit.by_name('Zeratul')                            # => Zeratul
p Unit.first_by_name('Zeratul')                      # => Zeratul
p Unit.all_by_name('Zeratul')                        # => [Zeratul]

Bang version, will raise error if nothing found.

p Unit.first!(name: 'Zeratul')                       # => Zeratul
p Unit.by_name!('Zeratul')                           # => Zeratul

Counting and existence checking.

p Unit.count                                         # => 3
p Unit.count(race: 'Protoss')                        # => 2
p Unit.exist?(name: 'Zeratul')                       # => true
p zeratul.exist?                                     # => true

You can use Query Builder for complex queries, let’s write sample query with and without it.

p Unit.all({race: 'Protoss'}, {sort: [[:name, -1]]}) # => [Zeratul, Tassadar]
p Unit.where(race: 'Protoss').sort([:name, -1]).all  # => [Zeratul, Tassadar]
p Unit.where(race: 'Protoss').sort(:name).all        # => [Tassadar, Zeratul]

Sometimes it’s handy to define frequently used queries on the model, such queries called scopes.

class Unit

Specifying alive scope to easilly select all alive units.

  scope :alive, status: 'alive'

If You provide block, it will be dynamically calculated for each query.

You can also specify default_scope it’s defined like normal scope but unlike it it’s always implicitly applied to all queries.

  scope(:terrans){{race: 'Terran'}}
end

Now we can use those scopes in queries. Scopes are chainable, so You can use any standard first, all, find_by, count method as well as another scopes.

p Unit.alive.count                                   # => 2
p Unit.alive.first                                   # => Zeratul
p Unit.alive.by_name('Zeratul')                      # => Zeratul
p Unit.alive.terrans.first                           # => Jim
p Unit.alive.where(race: 'Protoss').first            # => Zeratul

Using pagination.

per_page = 2
p Unit.paginate(1, per_page).sort(:name).all         # => [Jim, Tassadar]
p Unit.paginate(2, per_page).sort(:name).all         # => [Zeratul]

Mongo Model is tightly integrated with Driver, so You can also use its API for querying.

db = Mongo::Model.default_database
p db.units.first(name: 'Jim')                        # => Jim
p db.units.first(name: 'Jim').class                  # => Unit

Why there’s no support for

In this example we covered how to use standard MongoDB queries, dynamic finders, scopes and query builder.