Sort Query Results



Order by field value

  • Use OrderBy or OrderByDescending to order the results by the specified document-field.

List<Product> products = session
     // Make a dynamic query on the Products collection    
    .Query<Product>()
     // Apply filtering (optional)
    .Where(x => x.UnitsInStock > 10)
     // Call 'OrderBy', pass the document-field by which to order the results
    .OrderBy(x => x.UnitsInStock)
    .ToList();

// Results will be sorted by the 'UnitsInStock' value in ascending order,
// with smaller values listed first.
List<Product> products = await asyncSession
     // Make a dynamic query on the Products collection    
    .Query<Product>()
     // Apply filtering (optional)
    .Where(x => x.UnitsInStock > 10)
     // Call 'OrderBy', pass the document-field by which to order the results
    .OrderBy(x => x.UnitsInStock)
    .ToListAsync();

// Results will be sorted by the 'UnitsInStock' value in ascending order,
// with smaller values listed first.
List<Product> products = session.Advanced
     // Make a DocumentQuery on the Products collection    
    .DocumentQuery<Product>()
     // Apply filtering (optional)
    .WhereGreaterThan(x => x.UnitsInStock, 10)
     // Call 'OrderBy', pass the document-field by which to order the results
    .OrderBy(x => x.UnitsInStock)
    .ToList();

// Results will be sorted by the 'UnitsInStock' value in ascending order,
// with smaller values listed first.
from "Products"
where UnitsInStock > 10
order by UnitsInStock as long

Ordering Type:

  • By default, the OrderBy methods will determine the OrderingType from the property path expression
    and specify that ordering type in the generated RQL that is sent to the server.

  • E.g. in the above example, ordering by x => x.UnitsInStock will result in OrderingType.Long
    because that property data type is an integer.

  • Different ordering can be forced - see Force ordering type below.

Order by score

  • When querying with some filtering conditions, a basic score is calculated for each item in the results
    by the underlying indexing engine. (Read more about Lucene scoring here).

  • The higher the score value the better the match.

  • Use OrderByScore or OrderByScoreDescending to order by this score.

List<Product> products = session
    .Query<Product>()
     // Apply filtering
    .Where(x => x.UnitsInStock < 5 || x.Discontinued)
     // Call 'OrderByScore'
    .OrderByScore()
    .ToList();

// Results will be sorted by the score value
// with best matching documents (higher score values) listed first.
List<Product> products = await asyncSession
    .Query<Product>()
     // Apply filtering
    .Where(x => x.UnitsInStock < 5 || x.Discontinued)
     // Call 'OrderByScore'
    .OrderByScore()
    .ToListAsync();

// Results will be sorted by the score value
// with best matching documents (higher score values) listed first.
List<Product> products = session.Advanced
    .DocumentQuery<Product>()
     // Apply filtering
    .WhereLessThan(x => x.UnitsInStock, 5)
    .OrElse()
    .WhereEquals(x => x.Discontinued, true)
     // Call 'OrderByScore'
    .OrderByScore()
    .ToList();

// Results will be sorted by the score value
// with best matching documents (higher score values) listed first.
from "Products"
where UnitsInStock < 5 or Discontinued == true
order by score()

Get resulting score:

  • The score is available in the @index-score metadata property within each result.
    See how to get the resulting score from the metadata here.

  • To get the score details and see how it was calculated, you can request to include explanations in the query.
    See Include Query Explanations.

Order by random

  • Use RandomOrdering to randomize the order of the query results.

  • An optional seed parameter can be passed.

List<Product> products = session
    .Query<Product>()
    .Where(x => x.UnitsInStock > 10)
     // Call 'Customize' with 'RandomOrdering'
    .Customize(x => x.RandomOrdering())
     // An optional seed can be passed, e.g.:
     // .Customize(x => x.RandomOrdering('someSeed'))
    .ToList();

// Results will be randomly ordered.
List<Product> products = await asyncSession
    .Query<Product>()
    .Where(x => x.UnitsInStock > 10)
     // Call 'Customize' with 'RandomOrdering'
    .Customize(x => x.RandomOrdering())
     // An optional seed can be passed, e.g.:
     // .Customize(x => x.RandomOrdering('someSeed'))
    .ToListAsync();

// Results will be randomly ordered.
List<Product> products = session.Advanced  
    .DocumentQuery<Product>()
    .WhereGreaterThan(x => x.UnitsInStock, 10)
     // Call 'RandomOrdering'
    .RandomOrdering()
     // An optional seed can be passed, e.g.:
     // .RandomOrdering('someSeed')
    .ToList();

// Results will be randomly ordered.
from "Products"
where UnitsInStock > 10
order by random()
// order by random(someSeed)

Order by spatial

  • If your data contains geographical locations,
    spatial query results can be sorted based on their distance from a specific point.

  • See detailed explanation in Spatial Sorting.

Order by count (aggregation query)

  • The results of a group-by query can be sorted by the Count aggregation operation used in the query.

var numberOfProductsPerCategory = session
    .Query<Product>()
     // Make an aggregation query
    .GroupBy(x => x.Category)
    .Select(x => new
    {
        // Group by Category
        Category = x.Key,
        // Count the number of product documents per category
        Count = x.Count()
    })
     // Order by the Count value
    .OrderBy(x => x.Count)
    .ToList();

// Results will contain the number of Product documents per category
// ordered by that count in ascending order.
var numberOfProductsPerCategory = await asyncSession
    .Query<Product>()
     // Make an aggregation query
    .GroupBy(x => x.Category)
    .Select(x => new
    {
        // Group by Category
        Category = x.Key,
        // Count the number of product documents per category
        Count = x.Count()
    })
     // Order by the Count value
    .OrderBy(x => x.Count)
    .ToListAsync();

// Results will contain the number of Product documents per category
// ordered by that count in ascending order.
var numberOfProductsPerCategory = session.Advanced
    .DocumentQuery<Product>()
     // Group by Category
    .GroupBy("Category")
    .SelectKey("Category")
     // Count the number of product documents per category
    .SelectCount()
     // Order by the Count value
     // Here you need to specify the ordering type explicitly 
    .OrderBy("Count", OrderingType.Long)
    .ToList();

// Results will contain the number of Product documents per category
// ordered by that count in ascending order.
from "Products"
group by Category
order by count() as long
select key() as "Category", count()

Order by sum (aggregation query)

  • The results of a group-by query can be sorted by the Sum aggregation operation used in the query.

var numberOfUnitsInStockPerCategory = session
    .Query<Product>()
     // Make an aggregation query
    .GroupBy(x => x.Category)
    .Select(x => new
    {
        // Group by Category
        Category = x.Key,
        // Sum the number of units in stock per category
        Sum = x.Sum(x => x.UnitsInStock)
    })
     // Order by the Sum value
    .OrderBy(x => x.Sum)
    .ToList();

// Results will contain the total number of units in stock per category
// ordered by that number in ascending order.
var numberOfUnitsInStockPerCategory = await asyncSession
    .Query<Product>()
     // Make an aggregation query
    .GroupBy(x => x.Category)
    .Select(x => new
    {
        // Group by Category
        Category = x.Key,
        // Sum the number of units in stock per category
        Sum = x.Sum(x => x.UnitsInStock)
    })
     // Order by the Sum value
    .OrderBy(x => x.Sum)
    .ToListAsync();

// Results will contain the total number of units in stock per category
// ordered by that number in ascending order.
var numberOfUnitsInStockPerCategory = session.Advanced
    .DocumentQuery<Product>()
     // Group by Category
    .GroupBy("Category")
    .SelectKey("Category")
     // Sum the number of units in stock per category
    .SelectSum(new GroupByField
    {
        FieldName = "UnitsInStock",
        ProjectedName = "Sum"
    })
     // Order by the Sum value
     // Here you need to specify the ordering type explicitly 
    .OrderBy("Sum", OrderingType.Long)
    .ToList();

// Results will contain the total number of units in stock per category
// ordered by that number in ascending order.
from "Products"
group by Category
order by Sum as long
select key() as 'Category', sum(UnitsInStock) as Sum

Force ordering type

  • By default, the OrderBy methods will determine the OrderingType from the property path expression
    and specify that ordering type in the generated RQL that is sent to the server.

  • A different ordering can be forced by passing the ordering type explicitly to OrderBy or OrderByDescending.

  • The following ordering types are available:

    • OrderingType.Long
    • OrderingType.Double
    • OrderingType.AlphaNumeric
    • OrderingType.String (lexicographic ordering)
  • When using RQL directly, if no ordering type is specified, then the server defaults to lexicographic ordering.

Using alphanumeric ordering example:

  • When ordering mixed-character strings by the default lexicographical ordering
    then comparison is done character by character based on the Unicode values.
    For example, "Abc9" will come after "Abc10" since 9 is greater than 1.

  • If you want the digit characters to be ordered as numbers then use alphanumeric ordering
    where "Abc10" will result after "Abc9".

List<Product> products = session
    .Query<Product>()
     // Call 'OrderBy', order by field 'QuantityPerUnit'
     // Pass a second param, requesting to order the text alphanumerically
    .OrderBy(x => x.QuantityPerUnit, OrderingType.AlphaNumeric)
    .ToList();
List<Product> products = await asyncSession
    .Query<Product>()
     // Call 'OrderBy', order by field 'QuantityPerUnit'
     // Pass a second param, requesting to order the text alphanumerically
    .OrderBy(x => x.QuantityPerUnit, OrderingType.AlphaNumeric)
    .ToListAsync();
List<Product> products = session.Advanced
    .DocumentQuery<Product>()
     // Call 'OrderBy', order by field 'QuantityPerUnit'
     // Pass a second param, requesting to order the text alphanumerically
    .OrderBy(x => x.QuantityPerUnit, OrderingType.AlphaNumeric)
    .ToList();
from "Products"
order by QuantityPerUnit as alphanumeric

// Running the above query on the NorthWind sample data,
// would produce the following order for the QuantityPerUnit field:
// ================================================================

// "1 kg pkg."
// "1k pkg."
// "2 kg box."
// "4 - 450 g glasses"
// "5 kg pkg."
// ...

// While running with the default Lexicographical ordering would have produced:
// ============================================================================

// "1 kg pkg."
// "10 - 200 g glasses"
// "10 - 4 oz boxes"
// "10 - 500 g pkgs."
// "10 - 500 g pkgs."
// ...

Chain ordering

  • It is possible to chain multiple orderings in the query.
    Any combination of secondary sorting is possible as the fields are indexed independently of one another.

  • There is no limit on the number of sorting actions that can be chained.

  • This is achieved by using the ThenBy (ThenByDescending) and ThenByScore (ThenByScoreDescending) methods.

List<Product> products = session
    .Query<Product>()
    .Where(x => x.UnitsInStock > 10)
     // Apply the primary sort by 'UnitsInStock'
    .OrderByDescending(x => x.UnitsInStock)
     // Apply a secondary sort by the score (for products with the same # of units in stock)
    .ThenByScore()
     // Apply another sort by 'Name' (for products with same # of units in stock and same score)
    .ThenBy(x => x.Name)
    .ToList();

// Results will be sorted by the 'UnitsInStock' value (descending),
// then by score,
// and then by 'Name' (ascending).
List<Product> products = await asyncSession
    .Query<Product>()
    .Where(x => x.UnitsInStock > 10)
     // Apply the primary sort by 'UnitsInStock'
    .OrderByDescending(x => x.UnitsInStock)
     // Apply a secondary sort by the score (for products with the same # of units in stock)
    .ThenByScore()
     // Apply another sort by 'Name' (for products with same # of units in stock and same score)
    .ThenBy(x => x.Name)
    .ToListAsync();

// Results will be sorted by the 'UnitsInStock' value (descending),
// then by score,
// and then by 'Name' (ascending).
List<Product> products = session.Advanced
    .DocumentQuery<Product>()
    .WhereGreaterThan(x => x.UnitsInStock, 10)
     // Apply the primary sort by 'UnitsInStock'
    .OrderByDescending(x => x.UnitsInStock)
     // Apply a secondary sort by the score
    .OrderByScore()
     // Apply another sort by 'Name'
    .OrderBy(x => x.Name)
    .ToList();

// Results will be sorted by the 'UnitsInStock' value (descending),
// then by score,
// and then by 'Name' (ascending).
from "Products"
where UnitsInStock > 10
order by UnitsInStock as long desc, score(), Name

Custom sorters

  • The Lucene indexing engine allows you to create your own custom sorters.
    Custom sorters can be deployed to the server by either:

  • Once the custom sorter is deployed, you can sort the query results with it.

List<Product> products = session
    .Query<Product>()
    .Where(x => x.UnitsInStock > 10)
     // Order by field 'UnitsInStock', pass the name of your custom sorter class
    .OrderBy(x => x.UnitsInStock, "MySorter")
    .ToList();

// Results will be sorted by the 'UnitsInStock' value
// according to the logic from 'MySorter' class
List<Product> products = await asyncSession
    .Query<Product>()
    .Where(x => x.UnitsInStock > 10)
     // Order by field 'UnitsInStock', pass the name of your custom sorter class
    .OrderBy(x => x.UnitsInStock, "MySorter")
    .ToListAsync();

// Results will be sorted by the 'UnitsInStock' value
// according to the logic from 'MySorter' class
List<Product> products = session.Advanced
    .DocumentQuery<Product>()
    .WhereGreaterThan(x => x.UnitsInStock, 10)
     // Order by field 'UnitsInStock', pass the name of your custom sorter class
    .OrderBy(x => x.UnitsInStock, "MySorter")
    .ToList();

// Results will be sorted by the 'UnitsInStock' value
// according to the logic from 'MySorter' class
from "Products"
where UnitsInStock > 10
order by custom(UnitsInStock, "MySorter")

Syntax

// OrderBy overloads:
IOrderedQueryable<T> OrderBy<T>(string path, OrderingType ordering);
IOrderedQueryable<T> OrderBy<T>(Expression<Func<T, object>> path, OrderingType ordering);
IOrderedQueryable<T> OrderBy<T>(string path, string sorterName);
IOrderedQueryable<T> OrderBy<T>(Expression<Func<T, object>> path, string sorterName);

// OrderByDescending overloads:
IOrderedQueryable<T> OrderByDescending<T>(string path, OrderingType ordering);
IOrderedQueryable<T> OrderByDescending<T>(Expression<Func<T, object>> path, OrderingType ordering);
IOrderedQueryable<T> OrderByDescending<T>(string path, string sorterName);
IOrderedQueryable<T> OrderByDescending<T>(Expression<Func<T, object>> path, string sorterName);
Parameter Type Description
path string The name of the field to sort by
path Expression<Func<T, object>> A lambda expression to the field by which to sort
ordering QueryStatistics The ordering type that will be used to sort the results:
OrderingType.Long
OrderingType.Double
OrderingType.AlphaNumeric
OrderingType.String (default)
sorterName string The name of your custom sorter class