# Deep Filtering

[Modular Content](https://www.datocms.com/docs/content-modelling/modular-content.md) and [Structured Text](https://www.datocms.com/docs/content-modelling/structured-text.md) fields can embed [blocks](https://www.datocms.com/docs/content-modelling/blocks.md), which are dynamic, flexible, and repeatable structures. When referring to the Content Delivery API, deep filtering allows you to **filter records based on the content within their embedded blocks**.

## Activate deep filtering

Deep filtering is a feature that **needs to be explicitly enabled on a per-field basis.** This is to avoid complicating — and therefore slowing down — your GraphQL schema by generating a large number of types that will never actually be used.

To activate the feature, go to a field's editing modal, and enable the deep filtering option:

(Image content)

Once enabled, new filters become available in the GraphQL Content Delivery API for the specified field.

To be precise, there is a second necessary condition to see the newly activated GraphQL filters: the field must accept at least one block type. If the field does not allow embedding any block types within it, then deep filtering is not applicable — *there's nothing to filter!* — and therefore the GraphQL filters relative to deep filtering will not be present.

> [!PROTIP] Pro tip: Explore use cases for deep filtering
> Check out this [blog entry](https://www.datocms.com/blog/advanced-data-retrieval-with-deep-filtering.md) for an in-depth look at use cases where deep filtering can simplify accessing specific data without multiple API calls, enhancing performance and efficiency.

## Modular Content

In the following examples, let's consider a `blog_post` model with a `content` Modular Content field that accepts two types of blocks: `hero` and `product`.

#### Filter records containing at least one block matching the specified conditions

To retrieve `blog_post` records that contain a `product` block with a `name` equal to `"T-Shirt"`, and a `price` greater than 30, you can use the following GraphQL query:

```graphql
query {
  allBlogPosts(
    filter: {
      content: {
        any: { product: { name: { eq: "T-Shirt" }, price: { gt: 30 } } }
      }
    }
  ) {
    # ...
  }
}
```

In other words, within a field with deep filtering enabled, you can specify an `any` key where, for each block type that the field accepts, you can define one or more filtering conditions. The word "any" can be read as: *"find records where any product block respects these conditions"*.

The filtering conditions are the same ones discussed in the previous section on [Filtering records](https://www.datocms.com/docs/content-delivery-api/filtering-records.md), with the only difference being that since blocks don't have meta fields like ie. `_firstPublishedAt` they cannot be used in this context. The only meta key available for blocks is `id`.

#### Specifying conditions for multiple types of block

If you specify conditions for more than one type of block, then all conditions must be respected.

```graphql
query {
  allBlogPosts(
    filter: {
      content: {
        any: {
          product: { name: { eq: "T-Shirt" } }
          hero: { title: { matches: { pattern: "offer" } } }
        }
      }
    }
  ) {
    # ...
  }
}
```

The example above will search for all blog posts that have **both** a `product` block called `"T-Shirt"`, and a hero block with a title that contains the term `"offer"`.

#### Putting conditions in OR

If you want to apply logical OR conditions between various conditions, you can always use the `OR` filter.

The previous query can be modified to return blog posts that have either a "T-Shirt" `product` block or an "offer" `hero` block, like this:

```graphql
query {
  allBlogPosts(
    filter: {
      OR: [
        {
          content: {
            any: { product: { name: { eq: "T-Shirt" } } }
          }
        },
        {
          content: {
            any: { hero: { title: { matches: { pattern: "offer" } } } }
          }
        }
      ]
    }
  ) {
    # ...
  }
}
```

#### Filter records containing at least one block, of any kind

If you are only interested into filtering records that, in a particular field, contain at least one block, regardless of its type, you can use the `exists` filter:

```graphql
query {
  allBlogPosts(
    filter: {
      content: { exists: true }
    }
  ) {
    # ...
  }
}
```

Inverting the condition into `exists: false` will find all blog posts that don't have any block in the field.

#### Filter records containing at least one block of specified type

If you want to be more specific and filter records that contain at least one block of one or more specific types, then you can use the `"containsAny": true` filter. You can also search for records that do not contain any blocks of a specific type with`"containsAny": false`.

The following query returns all blog posts that contain at least one block of type `product`, but do not contain any blocks of type `hero`:

```graphql
query {
  allBlogPosts(
    filter: {
      content: {
        containsAny: { product: true, hero: false }
      }
    }
  ) {
    # ...
  }
}
```

## Structured Text

When deep filtering is *not* enabled on a Structured Text field, its GraphQL filters allow to filter by its textual content only, like this:

```graphql
query {
  allProducts(
    filter: {
      structuredTextField: {
        matches: { pattern: "bi(cycl|k)e", caseSensitive: false }
      }
    }
  ) {
    # ...
  }
}
```

However, when you activate deep filtering, the filter format will change, and the `value` argument will group together all filters related to the textual content.

To put it differently, when deep filtering is turned on, the previous query needs to be rewritten as:

```graphql
query {
  allProducts(
    filter: {
      structuredTextField: {
        value: { # this argument has been introduced
          matches: { pattern: "bi(cycl|k)e", caseSensitive: false }
        }
      }
    }
  ) {
    # ...
  }
}
```

> [!WARNING] This means a breaking change in GraphQL schema!
> We just saw that enabling deep filtering on a Structured Text field will cause a change to the associated GraphQL filter type. This means that existing GraphQL queries may need to be rewritten in order to avoid errors.
> 
> This is another reason why deep filtering is activable or not on a per-field basis: so that you are in control of when (and how) to introduce this change.
> 
> To avoid unpleasant surprises in production, it is a good idea to test the switch to deep filtering for Structured Text fields in a a [sandbox environment](https://www.datocms.com/docs/general-concepts/primary-and-sandbox-environments.md) first, and see if it breaks any of your existing GraphQL queries.

All the query possibilities in deep filtering mentioned above for the Modular Content fields also apply to the Structured Text fields.

The only distinction is that all the filter arguments related to blocks are nested inside the `blocks` argument:

```graphql
query {
  allProducts(
    filter: {
      structuredTextField: {
        blocks: {
          any: { cta: { title: { eq: "Subscribe!" } }
        },
        value: {
          matches: { pattern: "bi(cycl|k)e", caseSensitive: false }
        }
      }
    }
  ) {
    # ...
    }
  }
}
```

## Known Issues

> [!NOTE] Deep Filtering Technical Limitations
> #### Depth Limit:
> 
> Deep filtering is currently limited to only one level of depth. That is, you cannot filter records based on the content of blocks deeply nested inside other blocks. For example, if you have:
> 
> -   A modular content field
>     
>     -   A parent block with a "parent title" field and another modular content field called "child blocks"
>         
>         -   Inside a child block, you have another field called "child title"
>             
> 
> You **can** filter by the "parent title" but you **cannot** filter by the "child title".
> 
> #### Content Delivery API only:
> 
> Deep filtering is currently limited to the Content Delivery API (CDA / GraphQL). You cannot deep filter records in the Content Management API (CMA / REST).

## Related content in "Content Delivery API"

- [Content Delivery API Overview](https://www.datocms.com/docs/content-delivery-api.md)
- [Using the JavaScript CDA client](https://www.datocms.com/docs/content-delivery-api/your-first-request.md)
- [Authentication and permissions](https://www.datocms.com/docs/content-delivery-api/authentication.md)
- [Configuring requests: envs, drafts, strict mode, cache tags, etc.](https://www.datocms.com/docs/content-delivery-api/api-endpoints.md)
- [How to fetch records](https://www.datocms.com/docs/content-delivery-api/how-to-fetch-records.md)
- [Filtering records](https://www.datocms.com/docs/content-delivery-api/filtering-records.md)
- [Deep Filtering](https://www.datocms.com/docs/content-delivery-api/deep-filtering.md)
- [Ordering records](https://www.datocms.com/docs/content-delivery-api/ordering-records.md)
- [Pagination](https://www.datocms.com/docs/content-delivery-api/pagination.md)
- [Localization](https://www.datocms.com/docs/content-delivery-api/localization.md)
- [Direct vs. Inverse relationships](https://www.datocms.com/docs/content-delivery-api/inverse-relationships.md)
- [Hierarchical sorting (Tree-like collections)](https://www.datocms.com/docs/content-delivery-api/hierarchical-sorting.md)
- [Modular content fields](https://www.datocms.com/docs/content-delivery-api/modular-content-fields.md)
- [Structured text fields](https://www.datocms.com/docs/content-delivery-api/structured-text-fields.md)
- [Images and videos](https://www.datocms.com/docs/content-delivery-api/images-and-videos.md)
- [Filtering uploads](https://www.datocms.com/docs/content-delivery-api/filtering-uploads.md)
- [SEO and favicon](https://www.datocms.com/docs/content-delivery-api/seo-and-favicon.md)
- [Meta fields](https://www.datocms.com/docs/content-delivery-api/meta-fields.md)
- [Error codes & handling failures (CDA)](https://www.datocms.com/docs/content-delivery-api/errors.md)
- [CDA Technical Limits & Rate Limits](https://www.datocms.com/docs/content-delivery-api/technical-limits.md)
- [Complexity](https://www.datocms.com/docs/content-delivery-api/complexity.md)
- [Cache Tags](https://www.datocms.com/docs/content-delivery-api/cache-tags.md)
- [Custom Scalar Types](https://www.datocms.com/docs/content-delivery-api/custom-scalar-types.md)
- [Changelog](https://www.datocms.com/docs/content-delivery-api/changelog.md)