Queries#
CouchbaseOrm provides a rich query DSL inspired by ActiveRecord. A trivial query looks as follows:
Band.where(name: "Depeche Mode")
A more complex query utilizing various CouchbaseOrm features could be as follows:
Band.
where(:founded.gte => "1980-01-01").
where(name: [ "Tool", "Deftones" ]).
The query methods return CouchbaseOrm::Relation::CouchbaseOrm_Relation
objects, which are chainable
and lazily evaluated wrappers for Couchbase query language (SQL).
The queries are executed when their result sets are iterated. For example:
# Construct a CouchbaseOrm_Relation object:
Band.where(name: 'Deftones')
# => #<CouchbaseOrm::Relation::CouchbaseOrm_Relation
# where: [{"name"=>"Deftones"}]
# model: Band>
# Evaluate the query and get matching documents:
Band.where(name: 'Deftones').to_a
# => [#<Band _id: 5ebdeddfe1b83265a376a760, name: "Deftones", description: nil>]
Methods like first
and last
return the individual documents immediately.
Otherwise, iterating a CouchbaseOrm_Relation object with methods like each
or map
retrieves the documents from the server. to_a
can be used to force
execution of a query that returns an array of documents, literally converting
a CouchbaseOrm_Relation object to an Array.
When a query method is called on a CouchbaseOrm_Relation instance, the method returns a new CouchbaseOrm_Relation instance with the new conditions added to the existing conditions:
scope = Band.where(:founded.gte => "1980-01-01")
# => #<CouchbaseOrm::Relation::CouchbaseOrm_Relation
# where: [{"founded"=>{"$gte"=>"1980-01-01"}}]
# model: Band>
scope.where(:founded.lte => "2020-01-01")
# => #<CouchbaseOrm::Relation::CouchbaseOrm_Relation
# where: [{"founded"=>{"$gte"=>"1980-01-01", "$lte"=>"2020-01-01"}}]
# model: Band>
scope
# => #<CouchbaseOrm::Relation::CouchbaseOrm_Relation
# where: [{"founded"=>{"$gte"=>"1980-01-01"}}]
# class: Band>
Condition Syntax#
CouchbaseOrm supports three ways of specifying individual conditions:
Attribute syntax.
SQL syntax.
Symbol operator syntax.
All syntaxes support querying embedded documents using the dot notation. All syntaxes respect attribute types, if the attribute being queried is defined in the model class, and attribute aliases.
The examples in this section use the following model definition:
class Band < CouchbaseOrm::Base
attribute :name, type: String
attribute :founded, type: Integer
attribute :m, as: :member_count, type: Integer
belongs_to :manager
end
class Manager < CouchbaseOrm::Base
has_many :band
attribute :name, type: String
end
Attribute Syntax#
The simplest querying syntax utilizes the basic Ruby hashes. Keys can be symbols or strings, and correspond to attribute names in Couchbase documents:
Band.where(name: "Depeche Mode")
# => #<CouchbaseOrm::Relation::CouchbaseOrm_Relation
# where: [{"name"=>"Depeche Mode"}]
# model: Band>
# Equivalent to:
Band.where("name" => "Depeche Mode")
SQL Syntax#
An SQL operator may be specified on any attribute using the string syntax:
Band.where(founded: {'$gt' => 1980})
# => #<CouchbaseOrm::Relation::CouchbaseOrm_Relation
# where: [{"founded"=>{"$gt"=>1980}}]
# model: Band>
# Equivalent to:
Band.where('founded > 1980')
Logical Operations#
CouchbaseOrm supports where
and not
logical operations on
CouchbaseOrm_Relation
objects. These methods take one hash of conditions.
# and with conditions
Band.where(label: 'Trust in Trance').where(name: 'Astral Projection')
not
Behavior#
not
method can be called without arguments, in which case it will negate
the next condition that is specified. not
can also be called with one
or more hash conditions or CouchbaseOrm_Relation
objects, which will all be negated and
added to the criteria.
# not negates subsequent where
Band.not.where(name: 'Best')
# => {"name"=>{"$ne"=>"Best"}}
# not negates its argument
Band.not(name: 'Best')
# => {"name"=>{"$ne"=>"Best"}}
Ordering#
CouchbaseOrm provides the order
method on CouchbaseOrm_Relation
objects and its alias,
order_by
, to specify the ordering of documents. These methods take a
hash indicating which attributes to order the documents by, and whether to use
ascending or descending order for each attribute.
Band.order(name: asc)
# => #<CouchbaseOrm::Relation::CouchbaseOrm_Relation
# where: []
# order: [{"name"=>asc}]
# model: Band>
Band.order_by(name: :desc, description: :asc)
# => #<CouchbaseOrm::Relation::CouchbaseOrm_Relation
# where: []
# order: [{"name"=>:desc}, {"description"=>:asc}]
# class: Band
# embedded: false>
The direction may be specified with Symbol :asc
and :desc
for ascending
and descending, respectively
Finding By _id
#
CouchbaseOrm provides the find
method on CouchbaseOrm_Relation
objects to find documents
by their _id
values:
Band.find('5f0e41d92c97a64a26aabd10')
# => #<Band _id: 5f0e41d92c97a64a26aabd10, name: "Juno Reactor">
The find
method can accept an array of arguments.
In either case each of the arguments or array elements is taken to be an _id
value, and documents with all of the specified _id
values are returned in
an array:
Band.find('5f0e41d92c97a64a26aabd10', '5f0e41b02c97a64a26aabd0e')
# => [#<Band _id: 5f0e41b02c97a64a26aabd0e, name: "SUN Project", description: nil, likes: nil>,
#<Band _id: 5f0e41d92c97a64a26aabd10, name: "Juno Reactor", description: nil, likes: nil>]
Band.find(['5f0e41d92c97a64a26aabd10', '5f0e41b02c97a64a26aabd0e'])
# => [#<Band _id: 5f0e41b02c97a64a26aabd0e, name: "SUN Project", description: nil, likes: nil>,
#<Band _id: 5f0e41d92c97a64a26aabd10, name: "Juno Reactor", description: nil, likes: nil>]
If any of the _id
values are not found in the database, the behavior of
find
depends on the value of the quiet
configuration
option. If the option is set to false
, find
raises
CouchbaseOrm::Errors::DocumentNotFound
if any of the _id
s are not found.
If the option is set to true
and find
is given a single _id
to
find and there is no matching document, find
returns nil
. If the
option is set to false
and find
is given an array of ids to find
and some are not found, the return value is an array of documents that were
found (which could be empty if no documents were found at all).
Additional Query Methods#
CouchbaseOrm also has some helpful methods on criteria.
Operation |
Example |
---|---|
Get the total number of documents matching a filter, or the total number of documents in a collection. Note this will always hit the database for the count. |
Band.count
Band.where(name: "Photek").count
|
Iterate over all matching documents in the criteria. |
Band.where(members: 1).each do |band|
p band.name
end
|
Find a document by the provided attributes. If not found,
raise an error or return nil depending on the value of the
|
Band.find_by(name: "Photek")
Band.find_by(name: "Tool") do |band|
band.impressions += 1
end
|
Finds a single document given the provided criteria. Get a list of documents by passing in a limit argument. This method automatically adds a sort on _id. This can cause performance issues, so if the sort is undesirable, CouchbaseOrm_Relation#take can be used instead. |
Band.first
Band.where(:members.with_size => 3).first
Band.where(:members.with_size => 3).last
Band.first(2)
|
Same as count but caches subsequent calls to the database |
Band.length
Band.where(name: "FKA Twigs").size
|
Get all the values for the provided attribute. Returns nil for unset attributes and for non-existent attributes. |
Band.all.pluck(:name)
#=> ["Daft Punk", "Aphex Twin", "Ween"]
Band.all.pluck('address.city')
#=> ["Paris", "Limerick", "New Hope"]
# Using the earlier definition of Manager,
# expands out to "managers.name" in the query:
Band.all.pluck('managers.n')
#=> [ ["Berry Gordy", "Tommy Mottola"], [], ["Quincy Jones"] ]
# Accepts multiple attribute arguments, in which case
# the result will be returned as an Array of Arrays.
Band.all.pluck(:name, :likes)
#=> [ ["Daft Punk", 342], ["Aphex Twin", 98], ["Ween", 227] ]
|
Class Methods#
Class methods on models that return criteria objects are also treated like scopes, and can be chained as well.
class Band < CouchbaseOrm::Base
attribute :name, type: String
attribute :active, type: Boolean, default: true
def self.active
where(active: true)
end
end
Band.active