---
title: Nested queries
slug: cms-12/docs/nested-queries
docTags: 
createdAt: 2026-08-10T15:56:02.000Z
---

Nested queries in Optimizely Search & Navigation let you query an object and filter it on a collection marked as "nested." They are useful in solutions with Optimizely Commerce Connect and Optimizely Search & Navigation to manage search queries in large catalog structures.

## Add fields as nested types

:::hint{type="info"}
**Note**
Nested queries are allowed on *complex types* only. If you want to query a value type or a string collection, use the **Match** or **Exist** filter.
:::

You define a nested field as a list of complex types (`IEnumerable<TListItem>` where `TListItem:class`) that lets you query the parent object using filters matching individual items in the list (that is, query for **Teams** having a **Player** with the first name *Cristiano* and the last name *Ronaldo*).

To add fields as nested, use one of these conventions, depending on your requirements:

**Example:** Nested property on a class, for example `Team`.

```csharp
client.Conventions.NestedConventions.ForType<Team>().Add(team => team.Players);
```

**Example:** Nested property on an interface, for example, `IPlayers` (marks implementations of this interface as nested).

```csharp
client.Conventions.NestedConventions.ForInstancesOf<IPlayers>().Add(team => team.Players);
```

**Example:** Nested method or extension on a class, for example `ForeignPlayers()` on `Team`.

```csharp
// mark method or extension as indexed
client.Conventions.ForInstancesOf<Team>().IncludeField(team => team.ForeignPlayers()); 

client.Conventions.NestedConventions.ForType<Team>().Add(team => team.ForeignPlayers());
```

## Query on a nested property

Assume you have the following types (`Team` and `Player`).

```csharp
public class Team {
  public Team(string name) {
    TeamName = name;
    Players = new List<Player>();
  }
  public string TeamName {
    get;
    set;
  }
  public List<Player> Players {
    get;
    set;
  }
}

public class Player {
  public string FirstName {
    get;
    set;
  }
  public string LastName {
    get;
    set;
  }
  public int Salary {
    get;
    set;
  }
}
```

To query on a nested object property, use the nested `InField()` extension (for example, query for players having first name *Cristiano*):

```csharp
result = client.Search<Team>()
  .For("Cristiano")
  .InField(x => x.Players, x => x.FirstName)
  .GetResult();
```

Or by a native property and a nested object property (for example, query for team name or player first or last name):

```csharp
result = client.Search<Team>()
  .For("Cristiano")
  .InField(x => x.Name)
  .InField(x => x.Players, x => x.FirstName)
  .InField(x => x.Players, x => x.LastName)
  .GetResult();
```

## Filter on nested properties

To filter on nested object properties, use the nested `Filter()` extension (filter for teams with a player with first name *Cristiano* and last name *Ronaldo*).

```csharp
result = client.Search<Team>()
 .Filter(x => x.Players, p => p.FirstName.Match("Cristiano") & p.LastName.Match("Ronaldo"))
 .GetResult();
```

Or the `MatchItem()` extension.

```csharp
result = client.Search<Team>()
 .Filter(x => x.Players.MatchItem(p => p.FirstName.Match("Cristiano") & p.LastName.Match("Ronaldo")))
 .GetResult();
```

## Sort by nested properties

To sort by nested properties, use the `OrderBy()` extension and sort by specifying the nested object property to sort on and an optional filter to filter out objects in the list (that is, order teams by player's last name for players with first name *Cristiano*).

```csharp
result = client.Search<Team>()
 .OrderBy(x => x.Players, p => p.LastName, p => p.FirstName.Match("Cristiano"))
 .GetResult();
```

or

```csharp
result = client.Search<Team>()
 .OrderByDescending(x => x.Players, p => p.LastName, p => p.FirstName.Match("Cristiano"))
 .GetResult();
```

For `int/DateTime`, specify a `SortMode (Min/Max/Avg/Sum)` to determine how to treat multiple sort values. For example, to sort by maximum player salary on a team,

```csharp
result = client.Search<Team>()
 .OrderByDescending(x => x.Players, p => p.Salary, SortMode.Max)
 .GetResult();
```

## Create facets on nested properties

To create facets on nested object properties, use the `TermsFacetFor/HistogramFacetFor/DateHistogramFacetFor`-extensions by specifying a nested field and a property on the nested object (facet for the players' first names).

```csharp
result = client.Search<Team>()
 .TermsFacetFor(x => x.Players, x => x.FirstName)
 .GetResult();
```

Or, use an optional filter to filter out nested objects (facet for first names for players with the last name *Ronaldo*).

```csharp
result = client.Search<Team>()
 .TermsFacetFor(x => x.Players, x => x.FirstName, x => x.LastName.Match("Ronaldo"))
 .GetResult();
```

and fetch the result.

```csharp
facet = result.TermsFacetFor(x => x.Players, x => x.FirstName);
```

Use a custom facet name to create multiple facets on the same nested field and property.

```csharp
result = client.Search<Team>()
  .TermsFacetFor(x => x.Players, 
                 x => x.FirstName, 
                 x => x.LastName.Match("Ronaldo"), 
                 x => x.Name = "PlayersWithLastNameRonaldo")
  .TermsFacetFor(x => x.Players, 
                 x => x.FirstName, 
                 x => x.LastName.Match("Doe"), 
                 x => x.Name = "PlayersWithLastNameDoe")
  .GetResult();
```

and fetch the result.

```csharp
facet = result.Facets["PlayersWithLastNameRonaldo"] as TermsFacet;
facet = result.Facets["PlayersWithLastNameDoe"] as TermsFacet;
```
