Session: Querying: How to Stream Query Results
Query results can be streamed using the Stream
method from the Advanced
session operations. The query can be issued using either a static index, or it can be a dynamic one where it will be handled by an auto index.
Streaming query results does not support the include
feature.
Instead, the query should rely on the load
clause. See
example IV below.
Information
Entities loaded using Stream
will be transient (not attached to session).
Syntax
IEnumerator<StreamResult<T>> Stream<T>(IQueryable<T> query);
IEnumerator<StreamResult<T>> Stream<T>(
IQueryable<T> query,
out StreamQueryStatistics streamQueryStats);
IEnumerator<StreamResult<T>> Stream<T>(IDocumentQuery<T> query);
IEnumerator<StreamResult<T>> Stream<T>(
IDocumentQuery<T> query,
out StreamQueryStatistics streamQueryStats);
IEnumerator<StreamResult<T>> Stream<T>(IRawDocumentQuery<T> query);
IEnumerator<StreamResult<T>> Stream<T>(
IRawDocumentQuery<T> query,
out StreamQueryStatistics streamQueryStats);
Parameters | ||
---|---|---|
query | IQueryable, IDocumentQuery or IRawDocumentQuery | Query to stream results for. |
out streamQueryStats |
StreamQueryStatistics | Information about performed query. |
Return Value | |
---|---|
IEnumerator<StreamResult> | Enumerator with entities. |
Example I - Using Static Index
IQueryable<Employee> query = session
.Query<Employee, Employees_ByFirstName>()
.Where(x => x.FirstName == "Robert");
IEnumerator<StreamResult<Employee>> results = session.Advanced.Stream(query);
while (results.MoveNext())
{
StreamResult<Employee> employee = results.Current;
}
IQueryable<Employee> query = asyncSession
.Query<Employee, Employees_ByFirstName>()
.Where(x => x.FirstName == "Robert");
Raven.Client.Util.IAsyncEnumerator<StreamResult<Employee>> results = await asyncSession.Advanced.StreamAsync(query);
while (await results.MoveNextAsync())
{
StreamResult<Employee> employee = results.Current;
}
Example II - Dynamic Document Query
IDocumentQuery<Employee> query = session
.Advanced
.DocumentQuery<Employee>()
.WhereEquals(x => x.FirstName, "Robert");
StreamQueryStatistics streamQueryStats;
IEnumerator<StreamResult<Employee>> results = session.Advanced.Stream(query, out streamQueryStats);
while (results.MoveNext())
{
StreamResult<Employee> employee = results.Current;
}
IAsyncDocumentQuery<Employee> query = asyncSession
.Advanced
.AsyncDocumentQuery<Employee>()
.WhereEquals(x => x.FirstName, "Robert");
Raven.Client.Util.IAsyncEnumerator<StreamResult<Employee>> results = await asyncSession.Advanced.StreamAsync(query);
while (await results.MoveNextAsync())
{
StreamResult<Employee> employee = results.Current;
}
Example III - Dynamic Raw Query
IRawDocumentQuery<Employee> query = session
.Advanced
.RawQuery<Employee>("from Employees where FirstName = 'Robert'");
IEnumerator<StreamResult<Employee>> results = session.Advanced.Stream(query);
while (results.MoveNext())
{
StreamResult<Employee> employee = results.Current;
}
IAsyncRawDocumentQuery<Employee> query = asyncSession
.Advanced
.AsyncRawQuery<Employee>("from Employees where FirstName = 'Robert'");
Raven.Client.Util.IAsyncEnumerator<StreamResult<Employee>> results = await asyncSession.Advanced.StreamAsync(query);
while (await results.MoveNextAsync())
{
StreamResult<Employee> employee = results.Current;
}
Alternative to Using Includes
Streaming does not support the include
feature.
An include
clause in a query loads additional documents related to the primary target of the query.
These are stored in the session on the client side so that they can be accessed without an additional
query.
In a normal non-streamed query, included documents are sent at the end of results, after the
main targets and documents added with load
. This does not mesh well with streaming, which is
designed to allow transferring massive amounts of data, possibly over a significant amount of time.
Instead of getting related documents at the end of the stream, it is better to get them interspersed
with the other results.
Example IV
To include related documents in your query, add them using load
, then use select
to
retrieve the documents.
Because we used select
, the query results are now a projection containing more than
one entity. So on the client side, you need a projection class that matches the query result.
In this example, we query the Orders
collection and also load related Company
and
Employee
documents. With the select clause, we return all three objects. We have a class
called MyProjection
that has the three entity types as properties. We use this class to
store the results.
IRawDocumentQuery<MyProjection> query = session
.Advanced
.RawQuery<MyProjection>(@"from Orders as o
where o.ShipTo.City = 'London'
load o.Company as c, o.Employee as e
select {
order: o,
company: c,
employee: e
}");
IEnumerator<StreamResult<MyProjection>> results = session.Advanced.Stream(query);
while (results.MoveNext())
{
StreamResult<MyProjection> projection = results.Current;
}
IAsyncRawDocumentQuery<MyProjection> query = asyncSession
.Advanced
.AsyncRawQuery<MyProjection>(@"from Orders as o
where o.ShipTo.City = 'London'
load o.Company as c, o.Employee as e
select {
order: o,
company: c,
employee: e
}");
Raven.Client.Util.IAsyncEnumerator<StreamResult<MyProjection>> results = await asyncSession.Advanced.StreamAsync(query);
while (await results.MoveNextAsync())
{
StreamResult<MyProjection> projection = results.Current;
}
public class MyProjection
{
public Order order { get; set; }
public Employee employee { get; set; }
public Company company { get; set; }
}