Language
Java Node.JS
Article For
2.5 3.0 3.5 4.0 4.1 4.2 5.0 5.2

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");

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");

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'");

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
                                   }");


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; }
}