Skip to main content

Session: Querying: How to Project Query Results

Instead of pulling full documents in query results you can just grab some pieces of data from documents. You can also transform the projected results. The projections are defined in LINQ with the usage of:

Select

The most common way to perform a query with projection is to use the Select method. You can specify what fields from a document you want to retrieve and even provide complex expression.

Example I - Projecting Individual Fields of the Document

// request Name, City and Country for all entities from 'Companies' collection
var results = session
.Query<Company>()
.Select(x => new
{
Name = x.Name,
City = x.Address.City,
Country = x.Address.Country
})
.ToList();

Example II - Projecting Arrays and Objects

var results = session
.Query<Order>()
.Select(x => new
{
ShipTo = x.ShipTo,
Products = x.Lines.Select(y => y.ProductName),
})
.ToList();

Example III - Projection with Expression

var results = (from e in session.Query<Employee>()
select new
{
FullName = e.FirstName + " " + e.LastName,
}).ToList();

Example IV - Projection with let

var results = (from e in session.Query<Employee>()
let format = (Func<Employee, string>)(p => p.FirstName + " " + p.LastName)
select new
{
FullName = format(e)
}).ToList();

Example V - Projection with Calculation

var results = session
.Query<Order>()
.Select(x => new
{
Total = x.Lines.Sum(l => l.PricePerUnit * l.Quantity),
})
.ToList();

Example VI - Projection Using a Loaded Document

var results = (from o in session.Query<Order>()
let c = RavenQuery.Load<Company>(o.Company)
select new
{
CompanyName = c.Name,
ShippedAt = o.ShippedAt
}).ToList();

Example VII - Projection with Dates

var results = session
.Query<Employee>()
.Select(e => new
{
DayOfBirth = e.Birthday.Day,
MonthOfBirth = e.Birthday.Month,
Age = DateTime.Today.Year - e.Birthday.Year
})
.ToList();

Example VIII - Projection with Raw JavaScript Code

var results = from e in session.Query<Employee>()
select new
{
Date = RavenQuery.Raw<DateTime>("new Date(Date.parse(e.Birthday))"),
Name = RavenQuery.Raw(e.FirstName, "substr(0,3)"),
};

Example IX - Projection with Metadata

var results = (from e in session.Query<Employee>()
select new
{
Name = e.FirstName,
Metadata = RavenQuery.Metadata(e),
}).ToList();

SelectFields

The SelectFields method can only be used with the Document Query. It has two overloads:

// 1) By array of fields
IDocumentQuery<TProjection> SelectFields<TProjection>(params string[] fields);
// 2) By projection type
IDocumentQuery<TProjection> SelectFields<TProjection>();
  1. The fields of the projection are specified as a string array of field names. It also takes the type of the projection as a generic parameter.
var fields = new string[]{
"Name",
"Phone"
};

var results = session
.Advanced
.DocumentQuery<Company, Companies_ByContact>()
.SelectFields<ContactDetails>(fields)
.ToList();
  1. The projection is defined by simply passing the projection type as the generic parameter.
var results = session
.Advanced
.DocumentQuery<Company, Companies_ByContact>()
.SelectFields<ContactDetails>()
.ToList();

ProjectInto

This extension method retrieves all public fields and properties of the type given in generic and uses them to perform projection to the requested type. You can use this method instead of using Select together with all fields of the projection class.

Example

var results = session.Query<Company, Companies_ByContact>()
.ProjectInto<ContactDetails>()
.ToList();

OfType (As) - simple projection

OfType or As is a client-side projection. The easiest explanation of how it works is to take the results that the server returns and map them to given type. This may become useful when querying an index that contains fields that are not available in mapped type.

Example

// query index 'Products_BySupplierName' 
// return documents from collection 'Products' that have a supplier 'Norske Meierier'
// project them to 'Products'
List<Product> results = session
.Query<Products_BySupplierName.Result, Products_BySupplierName>()
.Where(x => x.Name == "Norske Meierier")
.OfType<Product>()
.ToList();

Projected entities (even named types) are not tracked by the session.

If the projected fields are stored inside the index itself (FieldStorage.Yes in the index definition), then the query results will be created directly from there instead of retrieving documents in order to project.