# Filters

> Source: https://docs.strapi.io/cms/api/rest/filters

The REST API filters feature allows filtering query results using operators like `$eq`, `$contains`, and `$between`, with support for complex filtering using `$and`, `$or`, and `$not`, as well as deep filtering across related content.

The [REST API](/cms/api/rest) offers the ability to filter results found with its ["Get entries"](/cms/api/rest#get-all) method.<br/>
Using optional Strapi features can provide some more filters:

- If the [Internationalization (i18n) plugin](/cms/features/internationalization) is enabled on a content-type, it's possible to filter by locale.
- If the [Draft & Publish](/cms/features/draft-and-publish) is enabled, it's possible to filter based on a `published` (default) or `draft` status.

:::tip

Strapi takes advantage of the ability of [the `qs` library](https://github.com/ljharb/qs) to parse nested objects to create more complex queries.

Use `qs` directly to generate complex queries instead of creating them manually. Examples in this documentation showcase how you can use `qs`.

You can also use the [interactive query builder](/cms/api/rest/interactive-query-builder) if you prefer playing with our online tool instead of generating queries with `qs` on your machine.

:::

Queries can accept a `filters` parameter with the following syntax:

`GET /api/:pluralApiId?filters[field][operator]=value`

The following operators are available:

| Operator        | Description                              |
| --------------- | ---------------------------------------- |
| `$eq`           | Equal                                    |
| `$eqi`          | Equal (case-insensitive)                 |
| `$ne`           | Not equal                                |
| `$nei`          | Not equal (case-insensitive)             |
| `$lt`           | Less than                                |
| `$lte`          | Less than or equal to                    |
| `$gt`           | Greater than                             |
| `$gte`          | Greater than or equal to                 |
| `$in`           | Included in an array                     |
| `$notIn`        | Not included in an array                 |
| `$contains`     | Contains                                 |
| `$notContains`  | Does not contain                         |
| `$containsi`    | Contains (case-insensitive)              |
| `$notContainsi` | Does not contain (case-insensitive)      |
| `$null`         | Is null                                  |
| `$notNull`      | Is not null                              |
| `$between`      | Is between                               |
| `$startsWith`   | Starts with                              |
| `$startsWithi`  | Starts with (case-insensitive)           |
| `$endsWith`     | Ends with                                |
| `$endsWithi`    | Ends with (case-insensitive)             |
| `$or`           | Joins the filters in an "or" expression  |
| `$and`          | Joins the filters in an "and" expression |
| `$not`          | Joins the filters in an "not" expression |

When several fields are passed in the `filters` object, they are implicitly combined with `$and` (e.g. `GET /api/restaurants?filters[stars][$gte]=3&filters[open][$eq]=true` only returns restaurants that are open and have at least 3 stars).

:::tip
`$and`, `$or` and `$not` operators can be nested inside one another.
:::

:::caution
By default, the filters can only be used from `find` endpoints generated by the Content-type Builder and the CLI.
:::

## Example: Find users having 'John' as a first name

#### GET /api/users — Find users having 

Use the $eq filter operator to find an exact match.

**cURL:**
```
GET /api/users?filters[username][$eq]=John
```

**JavaScript:**
```
const qs = require('qs');
const query = qs.stringify({
  filters: {
    username: {
      $eq: 'John',
    },
  },
}, {
  encodeValuesOnly: true, // prettify URL
});

await request(\`/api/users?\${query}\`);
```

**Response 200 OK:**
```json
{
  "data": [
    {
      "id": 1,
      "documentId": "znrlzntu9ei5onjvwfaalu2v",
      "username": "John",
      "email": "john@test.com",
      "provider": "local",
      "confirmed": true,
      "blocked": false,
      "createdAt": "2021-12-03T20:08:17.740Z",
      "updatedAt": "2021-12-03T20:08:17.740Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "pageSize": 25,
      "pageCount": 1,
      "total": 1
    }
  }
}
```

## Example: Find multiple restaurants with ids 3, 6,8

#### GET /api/restaurants — Find multiple restaurants with ids 3, 6, 8

Use the $in filter operator with an array of values to find multiple exact values.

**cURL:**
```
GET /api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8
```

**JavaScript:**
```
const qs = require('qs');
const query = qs.stringify({
  filters: {
    id: {
      $in: [3, 6, 8],
    },
  },
}, {
  encodeValuesOnly: true, // prettify URL
});

await request(\`/api/restaurants?\${query}\`);
```

**Response 200 OK:**
```json
{
  "data": [
    {
      "id": 3,
      "documentId": "ethwxjxtvuxl89jq720e38uk",
      "name": "test3"
    },
    {
      "id": 6,
      "documentId": "ethwxjxtvuxl89jq720e38uk",
      "name": "test6"
    },
    {
      "id": 8,
      "documentId": "cf07g1dbusqr8mzmlbqvlegx",
      "name": "test8"
    }
  ],
  "meta": {}
}
```

## Complex filtering

#### GET /api/books — Find books with 2 possible dates and a specific author

Combine $and and $or operators for complex filtering.

**cURL:**
```
GET /api/books?filters[$and][0][$or][0][date][$eq]=2020-01-01&filters[$and][0][$or][1][date][$eq]=2020-01-02&filters[$and][1][author][name][$eq]=Kai%20doe
```

**JavaScript:**
```
const qs = require('qs');
const query = qs.stringify({
  filters: {
    $and: [
      {
        $or: [
          {
            date: {
              $eq: '2020-01-01',
            },
          },
          {
            date: {
              $eq: '2020-01-02',
            },
          },
        ],
      },
      {
        author: {
          name: {
            $eq: 'Kai doe',
          },
        },
      },
    ],
  },
}, {
  encodeValuesOnly: true, // prettify URL
});

await request(\`/api/books?\${query}\`);
```

**Response 200 OK:**
```json
{
  "data": [
    {
      "id": 1,
      "documentId": "rxngxzclq0zdaqtvz67hj38d",
      "name": "test1",
      "date": "2020-01-01"
    },
    {
      "id": 2,
      "documentId": "kjkhff4e269a50b4vi16stst",
      "name": "test2",
      "date": "2020-01-02"
    }
  ],
  "meta": {}
}
```

:::note
The response above only contains a book's own attributes. The `author` relation traversed by the `$and` filter is not returned unless requested through the [`populate` parameter](/cms/api/rest/populate-select#population), for example by adding `&populate=author` to the request.
:::

## Deep filtering

:::note
- Relations, media fields, components, and dynamic zones are not populated by default. Use the `populate` parameter to populate these content structures (see [`populate` documentation](/cms/api/rest/populate-select#population))
- You can filter what you populate, you can also filter nested relations, but you can't use filters for polymorphic content structures (such as media fields and dynamic zones).
:::

:::caution
Querying your API with deep filters may cause performance issues.  If one of your deep filtering queries is too slow, we recommend building a custom route with an optimized version of the query.
:::

:::strapi Deep filtering with the various APIs
For examples of how to deep filter with the various APIs, please refer to [this blog article](https://strapi.io/blog/deep-filtering-alpha-26).
:::

#### GET /api/restaurants — Find restaurants owned by a chef who belongs to a 5-star restaurant

Use deep filtering to filter on a relation

**cURL:**
```
GET /api/restaurants?filters[chef][restaurants][stars][$eq]=5
```

**JavaScript:**
```
const qs = require('qs');
const query = qs.stringify({
  filters: {
    chef: {
      restaurants: {
        stars: {
          $eq: 5,
        },
      },
    },
  },
}, {
  encodeValuesOnly: true, // prettify URL
});

await request(\`/api/restaurants?\${query}\`);
```

**Response 200 OK:**
```json
{
  "data": [
    {
      "id": 1,
      "documentId": "cvsz61qg33rtyv1qljb1nrtg",
      "name": "GORDON RAMSAY STEAK",
      "stars": 5
    },
    {
      "id": 2,
      "documentId": "uh17h7ibw0g8thit6ivi71d8",
      "name": "GORDON RAMSAY BURGER",
      "stars": 5
    }
  ],
  "meta": {}
}
```

:::note
The response above mirrors the default REST output, which excludes the relations traversed by the filter. Add a [`populate` parameter](/cms/api/rest/populate-select#population) such as `&populate[chef][populate][restaurants]=true` to also return the `chef.restaurants` relation referenced in the filter.
:::
