
The simplest possible IQL query consists of a single item filter. The filter returns true (matched) or false (not matched).
## Elements of a filter

An item filter has three elements:
- A variable, which is an item attribute based on which you are filtering.
- An operator which defines how the attribute's value is compared with the filter value.
- A filter value to compare the attribute with.  
    This value can be a constant or inserted dynamically from a [context](/developers/iql/context).


  <pre><code class="language-plaintext">size     ==     10
      ^        ^      ^
  variable  operator  filterValue</code></pre>



<div class="admonition admonition-important"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

In POST request to APIs, the quotation marks around the filterValue must be escaped, for example:

<pre><code class="language-json">{
    "filter": "color == \"red\"",
    ...
}</code></pre>


</div></div></div>


## Data sources for filters

An item feed is the source for searches and recommendations. The feed is generated from a catalog in Synerise or an external XML source.

An item feed is indexed for the purpose of search and recommendation queries. In certain situations, the two indexes work differently. Those situations are described in this guide.


<div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

The indexes are updated periodically. An item that was recently added to the item feed is not immediately available in search/recommendation queries.

</div></div></div>


To learn more about configuring the item feed, see [AI Engine Configuration](/docs/settings/configuration/ai-engine-configuration).

## Item attributes

An attribute name is used as a variable, and its value is compared to a filter value. For example, the following filter is true when an item's `brand` attribute is `abcd`:
```
brand == "abcd"
```

**Variables are case-sensitive**, but filter values are not.  
For example, the filter `brand == "ABCD"` is the same as `brand == "abcd"`, but `Brand == "abcd"` filters only by an attribute named `Brand`, not `brand`.


<div class="admonition admonition-important"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

- In search requests, items can be filtered only by attributes which were defined as filterable when [configuring the search index](/docs/ai-hub/ai-search/define-attributes#filterable-attributes).  
- In recommendation requests, items can be filtered only by attributes which were defined as filterable when [configuring the AI model](/docs/settings/configuration/ai-engine-configuration/engine-configuration-for-recommendations).

</div></div></div>


Attributes with the following data type can be set as filterable:

| type | example(s) |
| --- | --- |
| string | `"foo"` |
| boolean | `true`;`false` |
| numeric | `12`; `12.34` |
| attributes in nested objects | `{"object":{"attr1":"value1","attr2":"value2"}}` |
| array of strings, numerics <br><br> Arrays must be type-consistent. If different data types (for example, strings and numbers) are included in one array, a filter may not work correctly.| `["foo","bar"]`<br>`[12,45]`<br>`[12.34,53.18]` |
### Example items

For the purpose of filter examples in this section, the following items are used:

<pre><code class="language-json">[
    {
        "itemId": "s1",
        "brand": "Abcd",
        "size": {
            "width": 10,
            "height": 20
        },
        "available": true,
        "tags": ["New", "Winter sale"]
        "promoted": "T",
        "price": {
            "value": 129.99
        },
        "winterPromotion": true,
        "category": "X &gt; Y &gt; Z",
        "additionalCategories": ["hiking", "warm", "L &gt; M &gt; N"]
    },
    {
        "itemId": "m1",
        "brand": "Efgh",
        "size": {
            "width": 5,
            "height": 17
        },
        "available": true,
        "tags": ["Winter sale"],
        "price": {
            "value": 249.99
        },
        "category": "X &gt; Y &gt; V"
    }
]</code></pre>


### Top level attributes
In order to access an attribute from the root level of the item's object, use the following syntax:
```
attributeName == filterValue
```
For example, `brand == "Abcd"`

### Nested attributes

To access a nested value, use dot notation:
```
objectName.attributeName == filterValue
```
For example, `size.width == 5`

### Indexing attributes in arrays (recommendations only)

When attributes are nested in arrays or arrays of objects, there is a difference in their indexing for the purposes of recommendation filters:
- all values of a textual attribute are indexed
- only the first value of a numeric attribute is indexed


  <div class="admonition admonition-important"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

  This logic does **not** affect [context](/developers/iql/context#item-context) items. Context items are taken from the item feed, not the index.

  </div></div></div>


  **Example 1**:

  Consider the following item:

  <pre><code class="language-json">{
    "itemId": "s1",
    "tags": ["New", "Winter sale"],
    "sizes": [10, 15]
  }</code></pre>

- The `tags` variable contains the `New` and `Winter sale` values.
- The `sizes` variable is `10`, because only the first number in an array is indexed.

  **Example 2**:

  Consider the following item:

  <pre><code class="language-json">{
    "itemId": "s1",
    "entries": [
        {
            "brand": "Abcd",
            "size": {
                "width": 10,
                "height": 20
            }
        },
        {
            "brand": "Xyz",
            "size": {
                "width": 15,
                "height": 25
            }
        }
    ]
  }</code></pre>

- The `entries.brand` variable contains the `Abcd` and `Xyz` values.
- The `entries.size.width` variable is `10`, because it's the width defined in the first object of an array of objects which contain the numerical `width` attribute.
### Category

`category` is a special type of attribute that describes a hierarchical structure.  
It is saved in the following format:
```
"X > Y > Z"
```
where X is the *top level category* and Z is a *leaf level category*.

To filter items by category, use the following syntax:
```
category == CATEGORY("X > Y > Z", 0)
```
The above example finds items which are in the `"X > Y > Z"` category or its subcategories.

For an explanation of the `0` argument and advanced operations on categories, see [the category function](/developers/iql/functions#category-function).

#### Additional categories

An item sometimes has a main *category* and a couple of additional categories to which it belongs, saved in the `additionalCategories` array.  

When the system creates a `category` filter, it combines the values from `category` (string) and `additionalCategories` (array of strings), hiding that complexity from the user.  

However, these categories are **not** combined in a [context](/developers/iql/context) item. If you want to use the context's additional categories in a filter, you must refer to them explicitly.

For example, the following filter checks an item's category against the context's category and additional categories:
```
(category == CATEGORY(context.category, 0)) OR (category == CATEGORY(context.additionalCategories, 0))
```

### Metrics

In IQL, you can use some pre-defined metrics which exist in all workspaces. Metrics are considered item attributes.

The following example checks if the value of a metric for the tested item is more than 10.
```
extra.metrics.9 > 10
```

The following metrics are available:
| Metric | Attribute name |
| --- | --- |
| Number of page visits in last 7 days | `extra.metrics.9` |
| Number of page visits in last 30 days | `extra.metrics.3` |
| Number of item purchases yesterday | `extra.metrics.6` |
| Number of item purchases in last 7 days | `extra.metrics.10` |
| Number of item purchases in last 30 days | `extra.metrics.1` |
| Number of item purchases on the same day last week | `extra.metrics.7` |
| Total value of item sales in last 30 days, with tax | `extra.metrics.2` |

## Operators

Operators are used to define the condition between the value of an attribute and the value to filter by. 
### Filtering against strings

Filter values are **not** case-sensitive. For example, `brand == "abcd"` is the same as `brand == "ABCD"`.
#### equals
The `==` operator checks if the strings are identical.
```
brand == "Abcd"
```

#### not equals

The `!=` operator checks if the strings are not identical.
```
brand != "Abcd"
```

### Filtering against numbers

#### value comparisons

The `<`, `<=`, `==`, `>=`, `>` operators compare the numbers.
```
size.width >= 10
```

#### value in range
The `FROM / TO` operator checks if a variable value is in a range between two values, including those values.
```
size.width FROM 6 TO 15
```

<div class="admonition admonition-tip"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" /></svg></div><div class="admonition-body"><div class="admonition-content">

An alternative way to build this filter is to [use the AND operator](/developers/iql/logic#and):
```
size.width >= 6 AND size.width <= 15
```

</div></div></div>



### Filtering against arrays

#### value in array

**Example 1:**

Checking if an item's attribute value exists in an array:

```
brand IN ["Abcd", "Efgh"]
```

<div class="admonition admonition-tip"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" /></svg></div><div class="admonition-body"><div class="admonition-content">

An alternative way to build this filter is to [use the OR operator](/developers/iql/logic#or):
```
brand == "Abcd" OR brand == "Efgh"
```

</div></div></div>


**Example 2:**

Checking if a value exists in an array, where the array is an item's attribute (`tags`):

The `IN` operator checks if a filter value is included in an array-type attribute's value.
```
"New" IN tags
```
The filter value can only be a string.  
Note that in this case, the filter value is to the left of the operator, and the variable (item attribute) is on the right.

#### array has value

The `HAS` operator checks if an array includes a variable (this is an alternative to the `IN` operator).
```
[9, 15] HAS size.width
```


<div class="admonition admonition-tip"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" /></svg></div><div class="admonition-body"><div class="admonition-content">

An alternative way to build this filter is to [use the OR operator](/developers/iql/logic#or):
```
size.width == 9 OR size.width == 15
```

</div></div></div>


#### value not in array
You can filter by checking if the value of a variable is NOT in an array.

```
brand NOT IN ["Abcd", "Efgh"]
```


<div class="admonition admonition-note"><div class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg></div><div class="admonition-body"><div class="admonition-content">

This filter isn't available in AI Search. Instead, you can use the ['NOT' operator](/developers/iql/logic#not) with the ['IN' filter](#value-in-array), for example:
```
NOT brand IN ["Abcd", "Efgh"]
```

</div></div></div>



### Filtering against booleans

#### equals

The `==` operator checks if boolean values are identical.
```
available == true

```
#### not equals

The `!=` operator checks if boolean values are not identical.
```
available != true
```

## What happens if an attribute does not exist in the item?

If an attribute does not exist in the item, its value is `null`.

#### Check if an attribute exists

The `IS DEFINED` operator allows you to check if an attribute exists and has a non-null value.

```
winterPromotion IS DEFINED
```