Conditional Filtering
-
Conditional filtering lets a single RQL query handle different combinations of search criteria based on query parameter values, instead of composing different query strings on the client.
-
Query parameters are values passed separately from the query text and referenced in RQL with
$,
such as$titleor$country. -
This feature is available only in RQL. It is not exposed through LINQ queries or DocumentQuery.
-
The RQL
when(condition, predicate)function applies a query predicate only whenconditionis true.- If
conditionevaluates totrue-
the predicate is applied. - If
conditionevaluates tofalse-
thewhen(...)clause is removed from the query expression and the predicate is not applied.
- If
-
The
conditionis evaluated server-side before documents are matched.
It is not evaluated per document and cannot inspect document fields.
The second argument,predicate, is a regular query predicate that is matched against documents. -
In this article:
When to use conditional filtering
-
Use conditional filtering when one query needs to support several optional search criteria, such as title, country, status, or date range.
-
Without
when, the client often builds the RQL dynamically, adding predicates only for parameters that were supplied.
Doing so creates many query-text variations and makes the query harder to read, test, and maintain. -
With
when, the client can pass all optional values as query parameters and keep one stable RQL query.
Each optional predicate is applied only when its corresponding condition istrue. -
Conditional filtering is useful when missing or
nullparameters should simply skip the specified predicate,
rather than require a different query string.
Basic example
-
The following query searches employees and conditionally applies two predicates:
one for title and one for country. -
The values are passed as query parameters.
In RQL,$titleuses the value passed by.AddParameter("title", title),
and$countryuses the value passed by.AddParameter("country", country). -
The query text stays the same for every request. Only the parameter values change.
- RawQuery
- RawQuery_async
- RQL
string? title = "Sales Representative"; // Use null to skip the title predicate.
string? country = "USA"; // Use null to skip the country predicate.
List<Employee> employees = session.Advanced
.RawQuery<Employee>(@"
from Employees
where when($title != null, Title == $title)
and when($country != null, Address.Country == $country)")
.AddParameter("title", title)
.AddParameter("country", country)
.ToList();string? title = "Sales Representative"; // Use null to skip the title predicate.
string? country = "USA"; // Use null to skip the country predicate.
List<Employee> employees = await asyncSession.Advanced
.AsyncRawQuery<Employee>(@"
from Employees
where when($title != null, Title == $title)
and when($country != null, Address.Country == $country)")
.AddParameter("title", title)
.AddParameter("country", country)
.ToListAsync();from Employees
where when($title != null, Title == $title)
and when($country != null, Address.Country == $country)
{ "title": "Sales Representative", "country": "USA" } -
When both parameters are non-null, both predicates are applied and the query behaves like:
from Employees
where Title == $title and Address.Country == $country -
When only
$countryis non-null, the title predicate is skipped and the query behaves like:from Employees
where Address.Country == $country -
When only
$titleis non-null, the country predicate is skipped and the query behaves like:from Employees
where Title == $title -
When both parameters are
nullor missing,
both conditional predicates are skipped and the query returns all employees, i.e.:from Employees
Combine when with 'and', 'or', and 'not'
-
A
whenclause can be combined with standardand,or, andnotoperators. -
When the condition is
true-
the predicate insidewhenparticipates in the surrounding boolean expression.When the condition is
false-
that predicate is skipped. -
The following table summarizes the resulting behavior:
Expression When condition is true When condition is false when(condition, Predicate1) and Predicate2Predicate1 and Predicate2Predicate2when(condition, Predicate1) or Predicate2Predicate1 or Predicate2Predicate2when(condition, Predicate1) and not Predicate2Predicate1 and not Predicate2not Predicate2Predicate2 and not when(condition, Predicate1)Predicate2 and not Predicate1Predicate2 -
If every predicate in the
whereclause is skipped -
the query behaves as if it has nowhereclause and returns all documents from the queried collection or index. -
Example - combine optional search criteria with a required predicate using
and:- RawQuery
- RawQuery_async
- RQL
List<Product> products = session.Advanced
.RawQuery<Product>(@"
from Products
where when($onlyInStock == true, UnitsInStock > 0)
and Discontinued == false")
.AddParameter("onlyInStock", true)
.ToList();List<Product> products = await asyncSession.Advanced
.AsyncRawQuery<Product>(@"
from Products
where when($onlyInStock == true, UnitsInStock > 0)
and Discontinued == false")
.AddParameter("onlyInStock", true)
.ToListAsync();from Products
where when($onlyInStock == true, UnitsInStock > 0)
and Discontinued == false
{ "onlyInStock": true }-
When
$onlyInStockistrue:
theUnitsInStock > 0predicate is applied, so the query returns non-discontinued products that are in stock. -
When
$onlyInStockisfalse:
theUnitsInStock > 0predicate is skipped, so the query returns all non-discontinued products.
Parameter and null handling
-
The condition compares query parameters (e.g.
$title,$country) against literal values.
The left-hand side of each comparison must be a parameter reference (a$-prefixed name). -
Missing parameters are treated as
null.
A parameter that was never supplied behaves exactly like a parameter explicitly set tonull. -
You can test for parameters that are
nullor missing with== nulland!= null:// Apply the Title predicate only when $title is non-null:
from Employees
where when($title != null, Title == $title)
// Apply a "no title set" predicate only when $title is null or missing:
from Employees
where when($title == null, Title == null) -
When a parameter is
null(or missing) and it is compared against a non-null value,
only!=evaluates totrue; all other operators evaluate tofalse.
For example, if$pis missing:$p != 5istrue, while$p == 5,$p > 5, etc. are allfalse.
Type handling
-
Comparisons are evaluated based on the type of the literal value being compared against,
and the parameter value is converted to match when a sensible conversion exists.
When no such conversion exists, the query fails withRavenException. -
Comparing against a number literal:
When comparing against a number literal, RavenDB converts betweenLongandDouble
(1 and 1.0 compare as equal), and all operators (==,!=,<,<=,>,>=) are supported.
A string parameter that holds a numeric value (e.g. "10") is parsed and compared as a number.
A parameter that cannot be converted to a number (a non-numeric string or a boolean) throwsRavenException.// Valid - RavenDB converts between Long and Double:
where when($longParam >= 10, ...)
// Valid - a numeric string parameter is compared as a number:
where when($numericStringParam == 10, ...) -
Comparing against a string literal:
When comparing against a string literal, the parameter must be a string.
A number or boolean parameter compared against a string literal throwsRavenException.
String value comparisons are case-insensitive (ordinal, ignore-case).// Valid - strings compare case-insensitively:
where when($stringParam == 'active', ...)
// Throws RavenException -
// string literal requires comparing against a string param
where when($numberParam == 'ten', ...) -
Comparing against a boolean literal:
When comparing against a boolean literal, only the equality operators==and!=are supported.
Using an inequality operator (<,<=,>,>=) throwsRavenException.
The parameter must also be a boolean; a non-boolean parameter throwsRavenException.// Valid - booleans with == / !=:
where when($booleanParam == false, ...)
// Throws RavenException - inequality on a boolean:
where when($booleanParam > false, ...) -
Comparing against
null:
A parameter isnullif it is explicitlynullor not supplied.When comparing against a
nullliteral, only==and!=are supported (other operators returnfalse):
$param == nullmatches a null/missing parameter;
$param != nullmatches any non-null value.When comparing against a non-null literal, a null/missing parameter makes
!=returntrue
and every other operator (including==) returnfalse- it never raises a type error.
Logical expressions in the condition
-
The condition can combine several parameter checks with
and,or,not, and parentheses.
Use parentheses to make the intended grouping explicit.- RawQuery
- RawQuery_async
- RQL
List<Employee> employees = session.Advanced
.RawQuery<Employee>(@"
from Employees
where when(($title == 'Sales Representative' or $title == 'Sales Manager')
and not ($includeAllTitles == true),
Title == $title)")
.AddParameter("title", "Sales Representative")
.AddParameter("includeAllTitles", false)
.ToList();List<Employee> employees = await asyncSession.Advanced
.AsyncRawQuery<Employee>(@"
from Employees
where when(($title == 'Sales Representative' or $title == 'Sales Manager')
and not ($includeAllTitles == true),
Title == $title)")
.AddParameter("title", "Sales Representative")
.AddParameter("includeAllTitles", false)
.ToListAsync();from Employees
where when(($title == 'Sales Representative' or $title == 'Sales Manager')
and not ($includeAllTitles == true),
Title == $title)
{ "title": "Sales Representative", "includeAllTitles": false }-
When
$titleis"Sales Representative"OR"Sales Manager"AND$includeAllTitlesisfalse:
theTitle == $titlepredicate is applied. -
When
$includeAllTitlesistrue, OR$titlehas another value:
theTitle == $titlepredicate is skipped.
Using 'in' and 'all in' in the condition
-
The condition can also use
inandall into test a parameter against a set of values. -
in-
the condition istruewhen the parameter value matches any of the listed values.
When the parameter is an array, the condition istruewhen the array shares at least one value with the list. -
all in-
when the parameter is an array, the condition istrueonly when every value in the parameter array is contained in the listed values. -
Example - apply an in-stock predicate only when the requested categories include
"Beverages"or"Condiments":- RawQuery
- RawQuery_async
- RQL
List<Product> products = session.Advanced
.RawQuery<Product>(@"
from Products
where when($categories in ('Beverages', 'Condiments'),
UnitsInStock > 0)")
.AddParameter("categories", new[] { "Beverages", "Seafood" })
.ToList();List<Product> products = await asyncSession.Advanced
.AsyncRawQuery<Product>(@"
from Products
where when($categories in ('Beverages', 'Condiments'),
UnitsInStock > 0)")
.AddParameter("categories", new[] { "Beverages", "Seafood" })
.ToListAsync();from Products
where when($categories in ('Beverages', 'Condiments'),
UnitsInStock > 0)
{ "categories": ["Beverages", "Seafood"] }-
When
$categoriescontains"Beverages"or"Condiments":
theUnitsInStock > 0predicate is applied. -
Otherwise:
theUnitsInStock > 0predicate is skipped, and all products are returned.
-
As with scalar string comparisons, string value matching in
inandall inconditions is case-insensitive. -
inandall incompare formatted string values, so some mixed parameter and list value types can match.
For example, a parameter value of"1"can matchin (1, 2, 3),
and a parameter value of1can matchin ('1', '2', '3').The comparison is textual: each value is formatted as a string before comparison.
Values that are numerically equal but have different string representations,
such as the string"1.0"and the number1(formatted as"1"), are not considered a match.
Restrictions
-
A
whencondition cannot contain anotherwhen
The condition (the first argument) ofwhen(condition, predicate)cannot include anotherwhen(...)call.
Attempting to usewheninside the condition, for example,when(when($b == 2, Number == 2), Number == 1), raises a parse error. -
The condition operates on parameters, not document fields
The left-hand side of each comparison in the condition must be a query parameter (a$-prefixed name).
The condition is evaluated once, at query-planning time, against the supplied parameters - it does not inspect document data. Document matching is done by the second argument, the predicate. -
AI agent parameter names
When the query is issued by an AI agent, parameter names in the condition are case-sensitive.
This applies to parameter names only; string comparisons remain case-insensitive.
Syntax
- RQL
when(<condition>, <predicate>)
| Parameter | Description |
|---|---|
| condition | A boolean expression evaluated server-side against query parameters. Each comparison has the form $param <operator> value.Supports ==, !=, <, <=, >, >=, in, all in, combined with and, or, not, and parentheses. |
| predicate | A regular query predicate, matched against the documents. Applied when condition is true; skipped when condition is false. |
-
The function name is case-insensitive in RQL:
when(...)andWHEN(...)are equivalent. -
Operator support per type:
Type Supported operators Notes Number ==,!=,<,<=,>,>=,in,all inRavenDB converts between LongandDouble(1 == 1.0).String ==,!=,<,<=,>,>=,in,all inString value matching is case-insensitive
(ordinal, ignore-case).Boolean ==,!=Using inequality operators throws a RavenException.Null == null,!= nullA missing parameter is treated as null.