Exploration Queries
-
Exploration Queries form an additional layer of filtering that can be applied to a dataset after its retrieval by Query, DocumentQuery, or Raw RQL, while the dataset is still held by the server.
-
The retrieved dataset is scanned and filtered without requiring or creating an index, providing a way to conduct one-time explorations without creating an index that would have to be maintained by the cluster.
-
You can filter the datasets retrieved by both Index queries and Collection queries.
-
Exploration queries need to be used with caution since scanning and filtering all the data retrieved by a query cost substantial server resources and user waiting time when large datasets are handled.
We recommend that you -
- Limit the number of records that an exploration query filters.
- Use where in recurring queries, so the query would use an index.
-
In this page:
filter
Exploration queries can be applied using -
Query.Filter
DocumentQuery.Filter
- RQL's
filter
keyword
The added filtering is parsed and executed by RavenDB's Javascript engine.
The provided filtering operations resemble those implemented by
where and can be further enhanced
by Javascript functions of your own.
Read here
about creating and using your own Javascript function in your filters.
When should exploration queries be used
filter
can be applied to a Collection query, like in:
from Employees as e
filter e.Address.Country = 'USA'
it can also be applied to queries handled by an index, e.g. -
// in a dynamic query via an auto-index
from Employees as e
where e.Title = 'Sales Representative'
filter e.Address.Country = 'USA'
// in a query that uses an index explicitly
from index 'Orders/ByCompany'
filter Count > 10
Both in a collection query and in a query handled by an index, the entire retrieved
dataset is scanned and filtered.
This helps understand when exploration queries should be used, why a Limit
should be set for the number of filtered records, and when where
should
be preferred:
When to use
Use filter
for an ad-hoc exploration of the retrieved dataset, that matches
no existing index and is not expected to be repeated much.
- You gain the ability to filter post-query results on the server side, for both collection queries and when an index was used.
- The dataset will be filtered without creating an unrequired index that the cluster
would continue updating from now on.
Limit the query, and prefer where
for recurring queries
Be aware that when a large dataset is retrieved, like the whole collection in
the case of a collection query, exploring it all using filter
would tax the server
in memory and CPU usage while it checks the filter condition for each query result,
and cost the user a substantial waiting time. Therefore -
- Limit the number of records that an exploration query filters, e.g.:
from Employees as e filter e.Address.Country = 'USA' filter_limit 500 // limit the number of filtered records
- Use where rather than
filter
for recurring filtering.
where
will use an index, creating it if necessary, to accelerate the filtering in subsequent queries.
Syntax
-
Query.Filter
IRavenQueryable<T> Filter<T>(this IRavenQueryable<T> source, Expression<Func<T, bool>> predicate, int limit = int.MaxValue);
Parameters Type Description source IRavenQueryable<T>
Filter
, defined as anIRavenQueryable
extension methodpredicate Expression<Func<T, bool>>
The condition by which retrieved records are filtered limit int
Limits the number of filtered records (Recommended)
Default: all retrieved records -
DocumentQuery.Filter
IDocumentQuery<T> Filter(Action<IFilterFactory<T>> builder, int limit = int.MaxValue);
Parameters Type Description builder Action<IFilterFactory<T>>
Your filter limit int
Limits the number of filtered records (Recommended)
Default: all retrieved records -
RQL
- In an RQL query, use:
Thefilter
keyword, followed by the filtering condition.
Thefilter_limit
option, followed by the max number of records to filter. - E.g. -
from Employees as e where e.Title = 'Sales Representative' filter e.Address.Country = 'USA' // filter the retrieved dataset filter_limit 500 // limit the number of filter records
- In an RQL query, use:
Usage examples
With collection queries
Use filter
with a collection query to scan and filter the entire collection.
var result = session.Query<Employee>()
.Filter(f => f.Address.Country == "USA", limit: 500)
.SingleOrDefault();
result = session.Advanced.DocumentQuery<Employee>()
.Filter(p => p.Equals(a => a.Address.Country, "USA"), limit: 500)
.SingleOrDefault();
result = session.Advanced.RawQuery<Employee>
("from Employees as e " +
"filter e.Address.Country = 'USA' " +
"filter_limit 500").SingleOrDefault();
Filtering a sizable collection will burden the server and prolong user waiting time.
Set a filter_limit
to restrict the number of filtered records.
With queries that use an index
Use filter
after a where
clause to filter the results retrieved by an index query.
var emp = session.Query<Employee>()
.Where(w => w.Title == "Sales Representative")
.Filter(f => f.Address.Country == "USA", limit: 500)
.SingleOrDefault();
emp = session.Advanced.DocumentQuery<Employee>()
.WhereEquals(w => w.Title, "Sales Representative")
.Filter(p => p.Equals(a => a.Address.Country, "USA"), limit: 500)
.SingleOrDefault();
emp = session.Advanced.RawQuery<Employee>
("from Employees as e" +
"where e.Title = $title" +
"filter e.Address.Country = $country" +
"filter_limit $limit")
.AddParameter("title", "Sales Representative")
.AddParameter("country", "USA")
.AddParameter("limit", 500)
.SingleOrDefault();
With projections
The filtered results can be projected using select
, like those of any other query.
var emp1 = session
.Query<Employee>()
.Filter(f => f.Address.Country == "USA", limit: 500)
.Select(x => new
{
FullName = x.FirstName + " " + x.LastName
})
.ToList();
var fullName = new string[]{
"FirstName",
"LastName"
};
var emp2 = session.Advanced.DocumentQuery<Employee>()
.Filter(p => p.Equals(a => a.Address.Country, "USA"), limit: 500)
.SelectFields<Employee>(fullName)
.ToList();
var emp3 = session.Advanced.RawQuery<Employee>
("from Employees as e" +
"filter startsWith(e.FirstName, 'A')" +
"select { FullName: e.FirstName + ' ' + e.LastName }");
With user-defined JavaScript functions (declare
)
You can define a Javascript function as part of your query using the
declare keyword, and
use it as part of your filter
condition to freely adapt the filtering
to your needs.
Here is a simple example:
// declare a Javascript function
declare function titlePrefix(r, prefix)
{
// Add whatever filtering capabilities you like
return r.Title.startsWith(prefix)
}
from Employees as e
// Filter using the function you've declared
filter titlePrefix(e, $prefix)
filter_limit 100