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 _ids 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