---
title: Where filter
slug: graph/docs/where-filter
docTags: 
createdAt: 2026-07-30T20:30:19.179Z
---

:::hint{type="info"}
**Note**
Optimizely Graph .NET Source SDK is optimized for CMS 12. Learn more about the [C# SDK for CMS 13](docId\:ZQSzbbACAIXmzMLIe4NIk).
:::

Use the `Where` method to apply [Where filter](docId\:PZVX-V2OoZlU9KPiAhDH-) conditions to a query result.

The parameters for the `Where` method are:

- A field name.
- An instance of the `IFilterOperator` interface that is combined and transformed to an Optimizely Graph filter query.

```csharp
var filterOperator = // create a concrete instance of IFilterOperator
new StringFilterOperators()
.Contains("value");

var query = queryBuilder
.ForType<MyDocument>()
  .Fields(x=>x.Property1, x=>x.Property2)
  .Where(x=>x.Property1, filterOperator)
 .ToQuery()
.BuildQueries();
```

`IFilterOperator` has four implementations:

- `NumericFilterOperators` – The filter operators for the Number field type. Optimizely Graph supports integer and float type.
- `BooleanFilterOperators` – The filter operators for the Boolean field type.
- `DateFilterOperators` – The filter operators for the DateTime field type.
- `StringFilterOperators` – The filter operators for the String field type.

## Filter expression

Optimizely Graph .NET Client supports built-in functions and Boolean logical operators in filter queries. The syntax is similar to the Search & Navigation (formerly FIND) client.

The following example filters on an `ArticlePage` to return items where `Name` contains "Optimizely" AND `Status` is "Published":

```csharp
var query = queryBuilder
    .ForType<ArticlePage>()
    .Fields(x => x.Name, x => x.MetaDescription)
    .Where(x => x.Name.Match("Optimizely") & x.Status.Eq("Published"))
    .ToQuery()
    .BuildQueries();
```

## Boolean filter

Boolean filters combine multiple conditions into a single `Where` clause so you can express AND, OR, and NOT logic without nesting separate filter calls. Use a Boolean filter when the condition you need cannot be expressed as a single field comparison. The Optimizely Graph .NET Client provides three Boolean filter classes:

- `AndFilter<T>` class – Wraps one or more conditions with an AND operator. Use the `And` method to combine many filters.
- `OrFilter<T>` class – Wraps one or more conditions with an OR operator. Use the `Or` method to combine many filters.
- `NotFilter<T>` class – Wraps one or more conditions with a NOT operator. Use the `Not` method to combine many filters.

Create one of the preceding classes using the `BooleanFilter` class. The static methods `AndFilter()`, `OrFilter()`, and `NotFilter()` create `AndFilter`, `OrFilter`, and `NotFilter` instances.

```csharp
var andFilter = BooleanFilter
.AndFilter<HomePage>()
.And(x=>x.Name.Eq("Your page name"))
.And(x=>x.Status.Eq("Published"));

var query = queryBuilder
.ForType<ArticlePage>()
  .Fields(x=>x.Name, x=>x.MetaDescription)
  .Where(andFilter)
.ToQuery()
.BuildQueries();
```

Use the basic logical operators `&` (AND), `|` (OR), and `!` (NOT) to create a Boolean filter.

```csharp
var andFilter = BooleanFilter
.AndFilter<HomePage>()
.And(x=>x.Name.Eq("Your page name"))
.And(x=>x.Status.Eq("Published"));

var query = queryBuilder
.ForType<ArticlePage>()
  .Fields(x=>x.Name, x=>x.MetaDescription)
  .Where(andFilter | x=>x.IsDraft.Eq(true)) // wrap OrFilter for combining 2 filters
.ToQuery()
.BuildQueries();
```

For complex filter queries, use a filter-operator variable.

```csharp
IFilterOperator filterForField1 = //create filter operator for type of Field1
IFilterOperator filterForField2 = //create filter operator for type of Field2
IFilterOperator filterForField3 = //create filter operator for type of Field3

var query = queryBuilder
.ForType<MyDocument>()
  .Fields(x=>x.Property1, x=>x.Property2)
  .Where(x=> x.Field1, filterForField1)
  .Where(x=>x.Field2, filterForField2)
  .Where(x=>x.Field3, filterForField3)
.ToQuery()
.BuildQueries();
```

### AND logic

When you use multiple filters on different fields, the SDK implicitly applies AND logic.

For example, to filter on `MyDocument` where `Field1.In(1,2,3)` AND `Field2.NotIn(4,5,6)`:

```csharp
var query =  queryBuilder
.ForType<MyDocument>()
  .Where(x=> x.Field1.In(1,2,3))
  .Where(x=> x.Field2.NotIn(4,5,6))
.ToQuery()
.BuildQueries();
```

### Multiple `Where` methods

Do not use multiple `Where` methods for filtering on the same field. For example:

```csharp
var query = queryBuilder
.ForType<MyDocument>()
  .Fields(x=>x.Property1, x=>x.Property2)
  .Where(x=> x.Property1.InRange(1,9))
  .Where(x=> x.Property1.NotIn(4,5,6)) //invalid query
.ToQuery()
.BuildQueries();
```

Instead, build the same functionality with one of the following approaches:

- Create an instance of `IFilterOperator` for multiple filters on one field:

```csharp
var filter = new NumericFilterOperators()
  .InRange(1,9)
  .NotIn(4,5,6);

var query = queryBuilder
.ForType<MyDocument>()
  .Fields(x=>x.Property1, x=>x.Property2)
  .Where(x=>x.Property1, filter) //Passing an IFilterOperator for Property1
.ToQuery()
.BuildQueries();
```

- Use Boolean logic operators to wrap the conditions:

```csharp
var andFilter = BooleanFilter
.AndFilter<MyDocument>()
.And(x=>x.Property1.InRange(1,9)/*condition1*/, x=> x.Property2.NotIn(4,5,6)/*condition2*/);

var query = queryBuilder
.ForType<MyDocument>()
  .Fields(x=>x.Property1, x=>x.Property2)
  .Where(andFilter)
.ToQuery()
.BuildQueries();
//Or maybe
var query = queryBuilder
.ForType<MyDocument>()
  .Fields(x=>x.Property1, x=>x.Property2)
  .Where(x => x.Property1.InRange(1,9) & x.Property1.NotIn(4,5,6)) // use AND logic conditionally
.ToQuery()
.BuildQueries();
```

## Filters on `IEnumerable\<T>` property

For a concise pattern, see the [Optimizely Graph Client: dealing with CMS data models for Query Builder](https://world.optimizely.com/blogs/manh-nguyen/dates/2024/4/optimizely-graph-client-dealing-with-cms-data-models-for-query-builder/) blog. The pattern described in the blog generates GraphQL queries with fewer round trips; see the blog comments for additional discussion.

The SDK provides the following options for working with `IEnumerable<T>` properties:

- If `T` is a simple type (`string`, `int`, `long`, `float`, `double`, `bool`, or `DateTime`), use it as you would a normal property:

```csharp
public class MyDocument{
  public IEnumerable<string> Ancestors{get;set;}
}

var query = queryBuilder
.ForType<MyDocument>()
  .Fields(x=>x.Name, x=>x.Url)
  .Where(x=> x.Ancestors.Eq("99d57529-61f2-47c0-80c0-f91eca6af1ac"))
.ToQuery()
.BuildQueries();
```

- If `T` is a complex type, there are two options.
  - Select `IEnumerable` property then the properties of `T`:

```javascript
public class Language{
  public string Name{get;set;}
  public string DisplayName{get;set;}
}
public class MyDocument{
  public IEnumerable<Language> ExistingLanguages{get;set;}
}

var query = queryBuilder
.ForType<MyDocument>()
  .Fields(x=>x.Name, x=>x.Url)
  .Where(x=> x.ExistingLanguages, f=> f.Name.Eq("en"))
.ToQuery()
.BuildQueries();
```

:::Paragraph{listStyleType="disc" indent="2"}
The most efficient way to filter on an `IEnumerable<T>` where `T` is a complex type is to add an extension method that returns `T` from the parent type. After you add the extension method, you can use the properties of `T` directly when selecting, filtering, or faceting. The extension method name must match the property name.
:::

```csharp
public static class CmsModelsExtension  
{  
      ...  
     public static ContentLanguageModel ExistingLanguages(this Content myprop)  
     {  
         return null;  
     }  
}  
//now you want to select properties in ExistingLanguages field, just use method ExistingLanguages() instead of property ExistingLanguages :  
query.Fields(x=> x.ExistingLanguages().Name, x.ExistingLanguages().DisplayName)  
//filters  
query.Where(x=> x.ExistingLanguages().Name.StartWith("e"))  
//facets  
query.Facet(x=> x.ExistingLanguages().Name.FacetLimit(10))
```

See [Tool tips: Optimizely Graph Client Tool and how to leverage CMS data models to build query](https://world.optimizely.com/blogs/manh-nguyen/dates/2024/4/optimizely-graph-client-dealing-with-cms-data-models-for-query-builder/) blog for more information.

:::hint{type="info"}
- **Note**
  If you have filter on properties of an `IEnumerable<T>` field, use the following example:

```csharp
var query = queryBuilder
.ForType<MyDocument>()
  .Fields(x=>x.Name, x=>x.Url)
  .Where(x=> x.ExistingLanguages, f=> f.Name.Eq("en"))
.ToQuery()
.BuildQueries();
```

- To build many conditions on one field, create an instance of `IFilterOperator`. For example, to filter language values that contain *"en"* but not *"English"* in `DisplayName`:

```csharp
var filterOperator = new StringFilterOperators().Contains("en").NotIn("English");
var query = queryBuilder
.ForType<MyDocument>()
  .Fields(x=>x.DisplayName, x=>x.Url)
  .Where(x=> x.ExistingLanguages, f=> f.DisplayName, filterOperator)
.ToQuery()
.BuildQueries();
```

- Now combine both of them for more complex query. Assume you want to filter more than one conditions on both `Name` and `DisplayName`, you should create a logical filter instance then combine them before use `.Where`.

```csharp
var operatorForName = new StringFilterOperators().Like("en").Boost(2);
var operatorForDisplayName = new StringFilterOperators().Eq("English").Boost(1);
var andFilter = BooleanFilter
.AndFilter<MyDocument>()
.And(x=>x.ExistingLanguages, f => f.Name, operatorForName)
.And(x=>x.ExistingLanguages, f => f.DisplayName, operatorForDisplayName);

var query = queryBuilder
.ForType<MyDocument>()
  .Fields(x=>x.Name, x=>x.Url)
  .Where(andFilter)
.ToQuery()
.BuildQueries();
```
:::
