Queries
A query is a request for data from an index. It specifies criteria that the data must meet to be included in the search results. For example, you might want to create queries like:
- ‘Return all active products with a price below 100’
- ‘Return all users who live in Denmark’.
Queries are created and managed using the queries widget on an index - click the Manage-link to open the query interface:
To create a query you click New query, then provide a name and select a source index:

And voila - you've created an empty query. Queries are used extensively both in backend and in frontend to identify products to work with or publish, users to send emails to, etc. You may also sometimes create queries elsewhere in the system - some of these are index queries and will appear on the index once created.
When you create queries it's important to understand the basics of how a query is constructed using the following elements:
- Parameters: Allow the query to accept dynamic input values, making it flexible
- Expressions: Define criteria to filter data
- Sortings: Sort query results based on specified fields
They are covered in the rest of the article.
Parameters
A parameter is a dynamic value that can be incorporated into a query, allowing the query to adapt to different inputs and conditions. Parameters are defined at runtime based on user inputs (e.g. facets) or other external sources, making your queries more dynamic and flexible.
In short - parameters don't do anything by themselves, but are filled from frontend and evaluated when the query is executed, for example when a user navigates between product groups and passes the GroupID to a parameter used in the query.
To create a parameter, open the query overview screen and click Manage on the parameters widget...
... and then add parameter and provide the parameter value, type and optionally a default value:

The value is simply the name of the parameter, and the type should match the kind of input you want to pass to the expression where you'll be using the parameter. If the field you're filtering on contains strings you should select System.String, if it contains boolean values select System.Boolean, if it contains DateTime objects select System.DateTime, etc.
If you're going to pass multiple values to a parameter, make sure to select the array-types (the ones ending in []).
Expressions
An empty query will return all data in the index. To find only a subset of the index content, you create sets of expressions which act as conditions and limit what's returned by the query.
An expression consists of:
- A field in the index that you want to set a condition for
- An operator that specifies the kind of comparison you want to make, e.g. equal or contains
- A test value which represents the value you're checking for
In the example here...
...we've created two expressions:
- The field Active should be equal to the constant value True
- The field Price should be LessThanOrEqual to the constant value 0
They're created as root expressions and set to use the operator AND, which means that all expressions inside the group (here the root-levek) must be true for an entry in the index to be returned by the query.
You can create additional expression groups and use the context menu for the group to switch it to an OR-group, negate it, and other more advanced stuff:

The settings work like this:
- AND-groups: All expressions inside the group must be true for an entry to be included in the results
- OR-groups: At least one of the expressions inside the group must be true for an entry to be included in the results
- Negate: All entries which don't match the expressions in the group are included in the result
Please note that if you include multiple expressions in a negated group, each expression is evaluated on it's own before being negated. This can be hard to wrap your mind around, but we pinky-promise we're returning the correct result at per Lucene.NET.
Fields
When you create an expression, the left side of the expression is always a field from the index you're querying.

The fields you can select are all the fields included in the index - for product indexes, this is typically all standard and custom product fields, a number of calculated fields which we've included by default, and any fields defined manually on the index such as a summary field intended for free-text search.
You can read more about this topic in the creating an index-article.
Operators
The middle part of an expression is the operator which defines the kind of comparison you're making between the value in the index field and the test value.

The operators you can select depend on the field selected on the expression, as only operators which make sense for the field data type will be selectable. Only numeric fields, for example, allow you to select the GreaterThan and LessThan operators, and so on.
Many of the operators are self-explanatory, but these may require a little more thought:
| Operator | Description | Example |
|---|---|---|
| Equal | Checks if the field value is equal to the test value. If the test value is an array, this operator works like the MatchAll operator |
Find products with a status of 'Active': Status Equal 'Active' |
| MatchAny | Checks if the field contains any of the test values | Find products in either 'Electronics', 'Books', or 'Clothing' categories: Category MatchAny ['Electronics', 'Books', 'Clothing'] |
| MatchAll | Checks if the field contains all the test values | Find products that have all tags 'New', 'OnSale', and 'Featured': Tags MatchAll ['New', 'OnSale', 'Featured'] |
| In | Works like MatchAny but only accepts arrays as the test value, whereas MatchAny also accepts non-arrays as test values |
Find users with IDs 101, 102, or 103: UserID In [101, 102, 103] |
| Contains | Looks for a partial match between the field value and the test value, matching values from their beginning (e.g., using [term]) |
Find products whose names start with 'Smart': Name Contains 'Smart' |
| ContainsExtended | Looks for a partial match between the field value and the test values, matching values anywhere (e.g., using [term]) This comes with a significant performance and memory overhead. |
Find products whose descriptions contain 'wireless': Description ContainsExtended 'wireless' |
| IsEmpty | Checks if a field is empty or not set | Find records where the Email field is empty: Email IsEmpty |
Test Values
The right side of an expression contains the test value - which is constructed from a type and a value.

First select a type - these are the types available to you:
| Type | Description | Use cases |
|---|---|---|
| Constant | A fixed unchanging value with a specific data type, e.g. a string or a DateTime value. | Filtering based on a fixed criteria, or setting a fixed threshold value like an upper or lower boundary value for a field |
| Macro | A dynamic placeholder which is replaced with a value derived from the current context at runtime e.g. CurrentUserID or a LanguageID from the website context | Returning session- or user-specific results |
| Parameter | A dynamic value passed to the query from an external source, such as through a search field, a facet, or other user inputs. | Allowing users to refine search results based on their input |
| Term | A static value already present on the field being queried. | Identifying all existing records that contain a specific term |
| Code | A calculated value passed to the query by a code-provider, e.g. DateTime.Now -30 days | Calculating more complex test values at runtime. Often used as an extensibility point. |
After selecting a type you define the value - this is done a little bit differently based on the type you selected:
When selecting a Type, specific options for that individual type will appear. To define the specific types:
- Constant: Select one of the available data types and enter a value
- Macro: Select the relevant macro
- Parameter: Select one of the parameters you have created
- Term: Use the dropdown to select one of the terms available on the selected index field
- Code: Select a code provider and configure it
Sorting
Finally, you can add sorting instructions directly on a query by selecting a number of fields and adding sort directions for them:

Typically, sorting is controlled at the app level when publishing query results to frontend via the Product Catalog for ViewModel or Query publisher apps. If a query is used elsewhere, such as in a custom extension, it can make sense to set up sorting directly on the query.
Tip
Please note, that if a field is analyzed, it cannot be sorted in a meaningful manner and will yield nonsense results. Instead, add a separate un-analyzed product name field to the index and use that to sort a query result.