Query Overview
-
Queries in RavenDB can be written with either of the following:
- LINQ - when querying with the session's
Query
method. - Low-level API - when querying with the session's
DocumentQuery
method. -
RQL:
- when querying with the session's
RawQuery
method. - when querying from the Query view in Studio.
- when querying with the session's
- LINQ - when querying with the session's
-
Queries defined with
Query
orDocumentQuery
are translated by the RavenDB client to RQL
when sent to the server.
-
All queries in RavenDB use an index to provide results, even when you don't specify one.
Learn more below. -
Queries that do Not specify which index to use are called Dynamic Queries.
This article displays examples of dynamic queries only.
For examples showing how to query an index see querying an index.
-
The entities returned by the query are 'loaded' and tracked by the Session.
Entities will Not be tracked when:- Query returns a projection
- Tracking is disabled
-
Query results are cached by default. To disable query caching see NoCaching.
-
Queries are timed out after a configurable time period. See query timeout.
Queries always provide results using an index
-
Queries always use an index to provide fast results regardless of the size of your data.
-
When a query reaches a RavenDB instance, the instance calls its query optimizer to analyze the query
and determine which index should be used to retrieve the requested data. -
Indexes allow to provide query results without scanning the entire dataset each and every time.
Learn more about indexes in indexes overview.
We differentiate between the following 3 query scenarios:
- Index query
- Dynamic query
- Full collection query
For each scenario, a different index type will be used.
-
Query type: Index query
Index used: Static-index -
You can specify which STATIC-index the query will use.
-
Static indexes are defined by the user, as opposed to auto-indexes that are created by the server
when querying a collection with some filtering applied. See Static-index vs Auto-index. -
Example RQL:
from index "Employees/ByFirstName" where FirstName == "Laura"
See more examples in querying an index.
2. Query a collection - with filtering:
-
Query type: Dynamic Query
Index used: Auto-index -
When querying a collection without specifying an index and with some filtering condition
(other than just the document ID) the query-optimizer will analyze the query to see if an AUTO-index
that can answer the query already exists, i.e. an auto-index on the collection queried with index-fields that match those queried. -
If such auto-index (Not a static one...) is found, it will be used to fetch the results.
-
Else, if no relevant auto-index is found,
the query-optimizer will create a new auto-index with fields that match the query criteria.
At this time, and only at this time, the query will wait for the auto-indexing process to complete.
Subsequent queries that target this auto-index will be served immediately. -
Note: if there exists an auto-index that is defined on the collection queried
but is indexing a different field than the one queried on,
then the query-optimizer will create a new auto-index that merges both the
fields from the existing auto-index and the new fields queried. -
Once the newly created auto-index is done indexing the data,
the old auto-index is removed in favor of the new one. -
Over time, an optimal set of indexes is generated by the query optimizer to answer your queries.
-
Example RQL:
from Employees where FirstName == "Laura"
See more examples below.
- Note: Counters and Time series are an exception to this flow.
Dynamic queries on counters and time series values don't create auto-indexes.
However, a static-index can be defined on Time series and Counters.
3. Query a collection - query full collection | query by ID:
-
Query type: Full collection Query
Index used: The raw collection (internal storage indexes) -
Full collection query:
-
When querying a collection without specifying an index and with no filtering condition,
then all documents from the specified collection are returned. -
RavenDB uses the raw collection documents in its internal storage indexes as the source for this query.
No auto-index is created. -
Example RQL:
from Employees
-
-
Query by document ID:
-
When querying a collection only by document ID or IDs,
then similar to the full collection query, no auto-index is created. -
RavenDB uses the raw collection documents as the source for this query.
-
Example RQL:
from Employees where id() == "employees/1-A"
See more examples below.
-
Session.Query
-
The simplest way to issue a query is by using the session's
Query
method which supports LINQ.
Both the LINQ method syntax and the LINQ query syntax are supported. -
The following examples show dynamic queries that do not specify which index to use.
Please refer to querying an index for other examples. -
Querying can be enhanced using these extension methods.
Query collection - no filtering
// This is a Full Collection Query
// No auto-index is created since no filtering is applied
List<Employee> allEmployees = session
.Query<Employee>() // Query for all documents from 'Employees' collection
.ToList(); // Execute the query
// All 'Employee' entities are loaded and will be tracked by the session
// This is a Full Collection Query
// No auto-index is created since no filtering is applied
List<Employee> allEmployees = await asyncSession
.Query<Employee>() // Query for all documents from 'Employees' collection
.ToListAsync(); // Execute the query
// All 'Employee' entities are loaded and will be tracked by the session
// This is a Full Collection Query
// No auto-index is created since no filtering is applied
// Query for all documents from 'Employees' collection
IRavenQueryable<Employee> query = from employee in session.Query<Employee>()
select employee;
// Execute the query
List<Employee> allEmployees = query.ToList();
// All 'Employee' entities are loaded and will be tracked by the session
// This is a Full Collection Query
// No auto-index is created since no filtering is applied
// Query for all documents from 'Employees' collection
IRavenQueryable<Employee> query = from employee in asyncSession.Query<Employee>()
select employee;
// Execute the query
List<Employee> allEmployees = await query.ToListAsync();
// All 'Employee' entities are loaded and will be tracked by the session
// This RQL is a Full Collection Query
// No auto-index is created since no filtering is applied
from "Employees"
Query collection - by ID
// Query collection by document ID
// No auto-index is created when querying only by ID
Employee employee = session
.Query<Employee>()
.Where(x => x.Id == "employees/1-A") // Query for specific document from 'Employees' collection
.FirstOrDefault(); // Execute the query
// The resulting 'Employee' entity is loaded and will be tracked by the session
// Query collection by document ID
// No auto-index is created when querying only by ID
Employee employee = await asyncSession
.Query<Employee>()
.Where(x => x.Id == "employees/1-A") // Query for specific document from 'Employees' collection
.FirstOrDefaultAsync(); // Execute the query
// The resulting 'Employee' entity is loaded and will be tracked by the session
// Query collection by document ID
// No auto-index is created when querying only by ID
// Query for specific document from 'Employees' collection
IRavenQueryable<Employee> query = from employee in session.Query<Employee>()
where employee.Id == "employees/1-A"
select employee;
// Execute the query
Employee employeeResult = query.FirstOrDefault();
// The resulting 'Employee' entity is loaded and will be tracked by the session
// Query collection by document ID
// No auto-index is created when querying only by ID
// Query for specific document from 'Employees' collection
IRavenQueryable<Employee> query = from employee in asyncSession.Query<Employee>()
where employee.Id == "employees/1-A"
select employee;
// Execute the query
Employee employeeResult = await query.FirstOrDefaultAsync();
// The resulting 'Employee' entity is loaded and will be tracked by the session
// This RQL queries the 'Employees' collection by ID
// No auto-index is created when querying only by ID
from "Employees" where id() == "employees/1-A"
Query collection - with filtering
// Query collection - filter by document field
// An auto-index will be created if there isn't already an existing auto-index
// that indexes this document field
List<Employee> employees = session
.Query<Employee>()
.Where(x => x.FirstName == "Robert") // Query for all 'Employee' documents that match this predicate
.ToList(); // Execute the query
// The resulting 'Employee' entities are loaded and will be tracked by the session
// Query collection - filter by document field
// An auto-index will be created if there isn't already an existing auto-index
// that indexes this document field
List<Employee> employees = await asyncSession
.Query<Employee>()
.Where(x => x.FirstName == "Robert") // Query for all 'Employee' documents that match this predicate
.ToListAsync(); // Execute the query
// The resulting 'Employee' entities are loaded and will be tracked by the session
// Query collection - filter by document field
// An auto-index will be created if there isn't already an existing auto-index
// that indexes this document field
// Query for all 'Employee' documents that match the requested predicate
IRavenQueryable<Employee> query = from employee in session.Query<Employee>()
where employee.FirstName == "Robert"
select employee;
// Execute the query
List<Employee> employees = query.ToList();
// The resulting 'Employee' entities are loaded and will be tracked by the session
// Query collection - filter by document field
// An auto-index will be created if there isn't already an existing auto-index
// that indexes this document field
// Query for all 'Employee' documents that match the requested predicate
IRavenQueryable<Employee> query = from employee in asyncSession.Query<Employee>()
where employee.FirstName == "Robert"
select employee;
// Execute the query
List<Employee> employees = await query.ToListAsync();
// The resulting 'Employee' entities are loaded and will be tracked by the session
// Query collection - filter by document field
// An auto-index will be created if there isn't already an existing auto-index
// that indexes the requested field
from "Employees" where FirstName == "Robert"
Query collection - with paging
// Query collection - page results
// No auto-index is created since no filtering is applied
List<Product> products = session
.Query<Product>()
.Skip(5) // Skip first 5 results
.Take(10) // Load up to 10 entities from 'Products' collection
.ToList(); // Execute the query
// The resulting 'Product' entities are loaded and will be tracked by the session
// Query collection - page results
// No auto-index is created since no filtering is applied
List<Product> products = await asyncSession
.Query<Product>()
.Skip(5) // Skip first 5 results
.Take(10) // Load up to 10 entities from 'Products' collection
.ToListAsync(); // Execute the query
// The resulting 'Product' entities are loaded and will be tracked by the session
// Query collection - page results
// No auto-index is created since no filtering is applied
IRavenQueryable<Product> query = (from product in session.Query<Product>()
select product)
.Skip(5) // Skip first 5 results
.Take(10); // Load up to 10 entities from 'Products' collection
// Execute the query
List<Product> products = query.ToList();
// The resulting 'Product' entities are loaded and will be tracked by the session
// Query collection - page results
// No auto-index is created since no filtering is applied
IRavenQueryable<Product> query = (from product in asyncSession.Query<Product>()
select product)
.Skip(5) // Skip first 5 results
.Take(10); // Load up to 10 entities from 'Products' collection
// Execute the query
List<Product> products = await query.ToListAsync();
// The resulting 'Product' entities are loaded and will be tracked by the session
// Query collection - page results
// No auto-index is created since no filtering is applied
from "Products" limit 5, 10 // skip 5, take 10
- By default, if the page size is not specified, all matching records will be retrieved from the database.
Session.Advanced.DocumentQuery
-
DocumentQuery
provides a full spectrum of low-level querying capabilities,
giving you more flexibility and control when making complex queries. -
Below is a simple DocumentQuery usage.
For a full description and more examples see:
Example:
// Query with DocumentQuery - filter by document field
// An auto-index will be created if there isn't already an existing auto-index
// that indexes this document field
List<Employee> employees = session
.Advanced.DocumentQuery<Employee>() // Use DocumentQuery
.WhereEquals(x => x.FirstName, "Robert") // Query for all 'Employee' documents that match this predicate
.ToList(); // Execute the query
// The resulting 'Employee' entities are loaded and will be tracked by the session
// Query with DocumentQuery - filter by document field
// An auto-index will be created if there isn't already an existing auto-index
// that indexes this document field
List<Employee> employees = await asyncSession
.Advanced.AsyncDocumentQuery<Employee>() // Use DocumentQuery
.WhereEquals(x => x.FirstName, "Robert") // Query for all 'Employee' documents that match this predicate
.ToListAsync(); // Execute the query
// The resulting 'Employee' entities are loaded and will be tracked by the session
// Query collection - filter by document field
// An auto-index will be created if there isn't already an existing auto-index
// that indexes the requested field
from "Employees" where FirstName = "Robert"
Session.Advanced.RawQuery
-
Queries defined with Query or DocumentQuery are translated by the RavenDB client to RQL
when sent to the server. -
The session also gives you a way to express the query directly in RQL using the
RawQuery
method.
Example:
// Query with RawQuery - filter by document field
// An auto-index will be created if there isn't already an existing auto-index
// that indexes this document field
List<Employee> employees = session
// Provide RQL to RawQuery
.Advanced.RawQuery<Employee>("from 'Employees' where FirstName = 'Robert'")
// Execute the query
.ToList();
// The resulting 'Employee' entities are loaded and will be tracked by the session
// Query with RawQuery - filter by document field
// An auto-index will be created if there isn't already an existing auto-index
// that indexes this document field
List<Employee> employees = await asyncSession
// Provide RQL to AsyncRawQuery
.Advanced.AsyncRawQuery<Employee>("from 'Employees' where FirstName = 'Robert'")
// Execute the query
.ToListAsync();
// The resulting 'Employee' entities are loaded and will be tracked by the session
Custom methods and extensions for LINQ
Available custom methods and extensions for the session's Query method:
- AggregateBy
- AnyAsync
- Count
- CountLazily
- Customize
- FirstAsync
- FirstOrDefaultAsync
- GroupByArrayValues
- GroupByArrayContent
- Highlight
- Include
- Intersect
- Lazily
- LazilyAsync
- LongCount
- MoreLikeThis
- OfType
- OrderByDistance
- OrderByDistanceDescending
- OrderByScore
- OrderByScoreDescending
- ProjectInto
- Search
- SingleAsync
- SingleOrDefaultAsync
- Spatial
- Statistics
- SuggestUsing
- ToListAsync
- ToArrayAsync
Syntax
// Overloads for querying a collection OR an index:
// ================================================
IRavenQueryable<T> Query<T>(string indexName = null,
string collectionName = null, bool isMapReduce = false);
IDocumentQuery<T> DocumentQuery<T>(string indexName = null,
string collectionName = null, bool isMapReduce = false);
// Overloads for querying an index:
// ================================
IRavenQueryable<T> Query<T, TIndexCreator>();
IDocumentQuery<T> DocumentQuery<T, TIndexCreator>();
// RawQuery:
// =========
IRawDocumentQuery<T> RawQuery<T>(string query);
Parameter | Type | Description |
---|---|---|
T | object |
|
TIndexCreator | string |
|
collectionName | string |
|
indexName | string |
|
isMapReduce | string |
|
query | string |
|
Return Value | |
---|---|
IRavenQueryable IDocumentQuery IRawDocumentQuery |
Instances exposing additional query methods and extensions |