Basics
Following article will introduce you into the querying. You probably read quite a few times by now, that indexes are used by RavenDB to satisfy queries, but what does that mean?
Query-flow
Each query in RavenDB must be done against index and the query-flow is as follows:
- First step, when query is issued, is to locate appropriate index. If our query specifies that index, the task is simple - use this index. Otherwise the query analysis is taking place and auto-index is created (if it does not exist already).
- When we have our index, we scan it for records that match query predicate.
- From each record server extracts appropriate fields. It always extracts
__document_id
field (stored by default). Additionally when projection is taking place, then fields defined in projection are extracted from index (if stored). - Next, if query is not a projection query, then we load a document from storage. Otherwise, if we stored all requested fields in index, then we use them and continue, if not, then document is loaded from storage and missing fields are fetched from it.
- In next step, our potential query results must pass read triggers.
- (Optional) If query indicates that transformer should be used, then all results that were not filtered out are processed by its projection function.
- Return results.
Querying using fluent syntax
RavenDB Client supports querying using fluent syntax (based on QueryDSL), this functionality can be accessed using session query
method and is the most common and basic method for querying the database.
Example I
Let's execute our first query and return all employees from Northwind database. To do that, we need to have a document store and opened session and specify a collection type that we want to query (in our case Employees
) by passing Employee
class as a parameter to query
method:
// load up to 128 entities from 'Employees' collection
List<Employee> results = session
.query(Employee.class)
.toList(); // send query
Notice that by specifying Employee
as a parameter, we are also defining a result type.
Safe By Default
By default, if page size is not specified, the value will be set to 128
.
Example II - filtering
To filter out results use suitable method e.g. where
:
// load up to 128 entities from 'Employees' collection
// where 'firstName' is 'Robert'
QEmployee e = QEmployee.employee;
List<Employee> results = session
.query(Employee.class)
.where(e.firstName.eq("Robert"))
.toList(); // send query
You can read more about filtering here.
Example III - paging
Paging is very simple, methods take
and skip
can be used:
// load up to 10 entities from 'Products' collection
// where there are more than 10 units in stock
// skip first 5 results
QProduct p = QProduct.product;
List<Product> results = session
.query(Product.class)
.where(p.unitsInStock.gt(10))
.skip(5)
.take(10)
.toList(); // send query
You can read more about paging here.
Example IV - querying specified index
In above examples we did not specify an index that we want to query, in that case RavenDB will try to locate an appropriate index or create a new one. You can read more about creating indexes here.
In order to specify a index, we need to pass it as a second parameter to query
method or pass index name as a parameter.
// load up to 128 entities from 'Employees' collection
// where 'FirstName' is 'Robert'
// using 'Employees/ByFirstName' index
QEmployee e = QEmployee.employee;
List<Employee> results = session
.query(Employee.class, Employees_ByFirstName.class)
.where(e.firstName.eq("Robert"))
.toList(); // send query
// load up to 128 entities from 'Employees' collection
// where 'FirstName' is 'Robert'
// using 'Employees/ByFirstName' index
QEmployee e = QEmployee.employee;
List<Employee> results = session
.query(Employee.class, "Employees/ByFirstName")
.where(e.firstName.eq("Robert"))
.toList(); // send query
Remember
If you are filtering by fields that are not present in index, exception will be thrown.
Low-level query access
To take a full control over your queries, we introduced a documentQuery
method that is available in advanced session operations. Basically it is a low-level access to the querying mechanism that user can take advantage of to shape queries according to needs.
Example
// load up to 128 entities from 'Employees' collection
// where 'FirstName' is 'Robert'
// using 'Employees/ByFirstName' index
QEmployee e = QEmployee.employee;
List<Employee> results = session
.advanced()
.documentQuery(Employee.class, Employees_ByFirstName.class)
.whereEquals(e.firstName, "Robert")
.toList(); // send query
Remarks
Information
You can check the API reference for the documentQuery
here.
Information
There are some differences between query
and documentQuery
and they are described in this article.