For global install run:
gem install --save ravendb
Or require ravendb
gem in your project's Gemfile
:
source 'https://rubygems.org'
gem 'ravendb'
- Declare document models as classes. Attributes should be just an instance variables accessible via
attr_accessor()
class Product
:attr_accessor :id, :title, :price, :currency,
:storage, :manufacturer, :in_stock,
:last_update
def initialize(
id = nil,
title = '',
price = 0,
currency = 'USD',
storage = 0,
manufacturer = '',
in_stock = false,
last_update = nil
)
@id = id
@title = title
@price = price
@currency = currency
@storage
@manufacturer = manufacturer
@in_stock = in_stock
@last_update = last_update
end
end
- Require
ravendb
gem and models classes in your application:
require 'ravendb'
require 'models/product'
- Configure document store:
RavenDB.store.configure do |config|
config.urls = ["database url"]
config.database = 'database name'
end
- Open a session:
session = RavenDB.store.open_session
- Do some actions with documents:
product = session.load('Products/1-A')
product.in_stock = true
- Call
save_changes
when you'll finish working with a session:
session.save_changes
- Also you can wrap all actions done with a session in a nested block:
RavenDB.store.open_session do |session|
product = session.load('Products/1-A')
product.in_stock = true
session.save_changes
end
product = Product.new('iPhone X', 999.99, 'USD', 64, 'Apple', true, DateTime.new(2017, 10, 1, 0, 0, 0))
RavenDB.store.open_session do |session|
product = session.store(product)
puts product.id # will output Products/<some number>-<some letter (server node tag)> e.g. Products/1-A
session.save_changes
end
RavenDB.store.open_session do |session|
product = session.load('Products/1-A')
puts product.title # iPhone X
puts product.id # Products/1-A
end
RavenDB.store.open_session do |session|
product = session.load('Products/1-A')
product.in_stock = false
product.last_update = DateTime.now
session.save_changes
product = session.load('Products/1-A')
puts product.in_stock.inspect # false
puts product.last_update # outputs current date
end
RavenDB.store.open_session do |session|
product = session.load('Products/1-A')
session.delete(product)
# or you can just do
# session.delete('Products/1-A')
session.save_changes
product = session.load('Products/1-A')
puts product.inspect # nil
end
- Create
RavenDB::DocumentQuery
instance usingquery
method of session:
query = session.query({
:collection => 'Products', # specify which collection you'd like to query
# optionally you may specify an index name for querying
# :index_name => 'PopularProductsWithViewsCount'
})
- Apply conditions, ordering etc. Query supports chaining calls:
query
.wait_for_non_stale_results
.using_default_operator(RavenDB::QueryOperator::AND)
.where_equals('manufacturer', 'Apple')
.where_equals('in_stock', true)
.where_between('last_update', DateTime.strptime('2017-10-01T00:00:00', '%Y-%m-%dT%H:%M:%S'), DateTime::now)
.order_by('price')
- Finally, you may get query results:
documents = query.all
- If you used
select_fields
method in in query, pass document class (or class name) as:document_type
parameter in the query options:
products_with_names_only = session.query({
:document_type => Product,
:collection => 'Products'
})
.select_fields(['name'])
.wait_for_non_stale_results
.all
Method | RQL / description |
---|---|
select_fields(fields, projections = nil) |
select field1 [as projection1], ... |
distinct |
select distinct |
where_equals(field_name, value,
exact = false) |
where fieldName = <value> |
where_not_equals(field_name, value,
exact = false) |
where fieldName != <value> |
where_in(field_name, values, exact = false) |
where fieldName in (<value1>, <value2>, ...) |
where_starts_with(field_name, value) |
where startsWith(fieldName, '<value>') |
where_ends_with(field_name, value) |
where endsWith(fieldName, '<value>') |
where_between(field_name, from, to,
exact = nil) |
where fieldName BETWEEN <start> AND <end> |
where_greater_than(field_name, value,
exact = nil) |
where fieldName > <value> |
where_greater_than_or_equal(field_name,
value, exact = nil) |
where fieldName >= <value> |
where_less_than(field_name, value,
exact = nil) |
where fieldName < <value> |
where_less_than_or_equal(field_name,
value, exact = nil) |
where fieldName <= <value> |
where_exists(field_name) |
where exists(fieldName) |
contains_any(field_name, values) |
where fieldName in (<value1>, <value2>, ...) |
contains_all(field_name, values) |
where fieldName all in (<value1>, <value2>, ...) |
search(field_name, search_terms,
operator = RavenDB::SearchOperator::OR) |
Performs full-text search |
open_subclause |
Opens subclause (
|
close_subclause |
Closes subclause ) |
negate_next |
Adds not before next condition |
and_also |
Adds and before next condition |
or_else |
Adds or before next condition |
using_default_operator(operator) |
Sets default operator (which will be used if no and_also / or_else was called. Just after query instantiation, OR is used as default operator. Default operator can be changed only before adding any conditions |
order_by(field, ordering_type = nil) |
order by field |
order_by_descending(field,
ordering_type = nil) |
order by field desc |
random_ordering(seed = nil) |
order by random() |
take(count) |
Limits the number of result entries to count |
skip(count) |
Skips first count results |
first |
Returns first document from result set |
single |
Returns single document matching query criteria. If there are no such document or more then one - throws an Exception |
all |
Returns all documents from result set (considering take / skip options) |
count |
Returns count of all documents matching query criteria (non-considering take / skip options) |
- Instantiate
RavenDB::StoreAuthOptions
. Pass contents of the .pem certificate and passphrase (optional) to constructor:
certificate = <<CERTIFICATE
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
CERTIFICATE
auth_options = RavenDB::StoreAuthOptions.new(certificate)
#or
auth_options = RavenDB::StoreAuthOptions.new(certificate, "my passphrase")
- Pass
RavenDB::StoreAuthOptions
instance toauth_options
config option when you're configuring store:
RavenDB.store.configure do |config|
config.urls = ["database url"]
config.database = 'database name'
config.auth_options = RavenDB::StoreAuthOptions.new(certificate)
end
- if no
RavenDB::StoreAuthOptions
was provided and you're trying to work with secured server, anRavenDB::NotSupportedException
will be raised during store initialization - if certificate is invalid or doesn't have permissions for specific operations, an
RavenDB::AuthorizationException
will be raised
You can attach binary files to documents.
- To attach a file, use
RavenDB::PutAttachmentOperation
. Pass document id, attachment name (it can be just a file name), content type and file contents:
require 'ravendb'
# ...
file_name = './iphone-x.png'
store.operations.send(
RavenDB::PutAttachmentOperation.new(
document_id: 'Products/1-A',
name: File.basename(file_name),
stream: File.read(file_name),
content_type: 'image/png'
)
)
- To read an attachment, use
RavenDB::GetAttachmentOperation
. Pass document id and attachment name. File contents will be stored as:stream
key of response:
require 'ravendb'
# ...
file_name = 'iphone-x.png'
attachment_result = store.operations.send(
RavenDB::GetAttachmentOperation.new(
document_id: 'Products/1-A',
name: file_name,
type: RavenDB::AttachmentType::DOCUMENT
)
)
file = File.new("./${file_name}", "wb")
file.write(attachment_result[:stream])
file.close
- To delete an attachment, use
RavenDB::DeleteAttachmentOperation
. Pass document id and attachment name.
require 'ravendb'
# ...
file_name = 'iphone-x.png'
store.operations.send(
RavenDB::DeleteAttachmentOperation.new(
document_id: 'Products/1-A',
name: file_name
)
)
By default document id is stored onto id
property of document. But you can define which name of id property should be for specific document types.
- Call
store.conventions.add_id_property_resolver
and pass an callback block. It accepts document info hash and should return id property name:
# models/item.rb
class Item
attr_accessor :item_id, :item_title, :item_options
def initialize(item_id = nil, item_title = "", item_options = [])
@item_id = item_id
@item_title = item_title
@item_options = item_options
end
end
# main.rb
require 'ravendb'
# ...
store.conventions.add_id_property_resolver do |document_info|
case document_info[:document_type]
when Item.name
'item_id'
else
'id'
end
end
- Now client will read/fill
item_id
property with document id while doing CRUD operations:
session = store.open_session
session.store(Item.new(nil, 'First Item', [1, 2, 3]))
session.save_changes
puts item.item_id # Items/1-A
session = store.open_session
item = session.load('Items/1-A')
puts item.item_id # Items/1-A
puts item.item_title # First Item
puts item.item_options.inspect # [1, 2, 3]
You can define custom serializers if you need to implement your own logic for convert attributes names/values for specific document types.
- Define your serializer as an class derived from
RavenDB::AttributeSerializer
. Overrideon_serialized
/on_unserialized
methods:
class CustomAttributeSerializer < RavenDB::AttributeSerializer
def on_serialized(serialized)
end
def on_unserialized(serialized)
end
end
Where serialized
attribute is a hash with the following structure:
{
:source => <source json hash / document model>,
:target => <target json hash / document model>,
:original_attribute => <original attribute name>,
:serialized_attribute => <target attribute name>,
:original_value => <original attribute value>,
:serialized_value => <target attribute value>,
:metadata => <document metadata hash>
}
- Store target attribute name/value into the
serialized_attribute
/serialized_value
properties ofserialized
parameter:
# serializers/custom.rb
class CustomAttributeSerializer < RavenDB::AttributeSerializer
def on_serialized(serialized)
metadata = serialized[:metadata]
case metadata['Raven-Ruby-Type']
when TestCustomSerializer.name
serialized[:serialized_attribute] = serialized[:original_attribute].camelize(:lower)
if serialized[:original_attribute] == 'item_options'
serialized[:serialized_value] = serialized[:original_value].join(",")
end
else
nil
end
end
def on_unserialized(serialized)
metadata = serialized[:metadata]
case metadata['Raven-Ruby-Type']
when TestCustomSerializer.name
serialized[:serialized_attribute] = serialized[:original_attribute].underscore
if serialized[:original_attribute] == 'itemOptions'
serialized[:serialized_value] = serialized[:original_value].split(",").map { |option| option.to_i }
end
else
nil
end
end
end
- Pass your serializer object to
conventions.add_attribute_serializer
:
require 'ravendb'
require './serializers/custom'
store.conventions.add_attribute_serializer(serializer)
sesssion = store.open_session
session.store(Item.new(nil, 'First Item', [1, 2, 3]))
session.save_changes
session = store.open_session
item = session.load('Items/1-A')
puts item.item_id # Items/1-A
puts item.item_title # First Item
puts item.item_options.inspect # [1, 2, 3]
response = store.get_request_executor.execute(RavenDB::GetDocumentCommand.new('Items/1-A'))
raw_document = response['Results'].first
puts raw_document['@metadata']['@id'] # Items/1-A
puts raw_document['itemTitle'] # First Item
puts raw_document['itemOptions'] # "1,2,3"
URL=<RavenDB server url including port> [CERTIFICATE=<path to .pem certificate> [PASSPHRASE=<.pem certificate passphrase>]] rake test