# Advanced Data Retrieval With Deep Filtering in DatoCMS

Posted on [date: 2023-12-19T11:34:06.764+01:00] by Antonello Zanini

The [introduction of deep filtering](https://www.datocms.com/blog/introducing-deep-filtering-a-new-feature-for-enhanced-content-filtering.md) to DatoCMS has given developers the ability to filter records based on the content within their embedded blocks. This new feature of the Content Delivery API opens up many possibilities, reducing the need to make multiple API calls to get the desired data.

In this guide, you will understand what deep filtering is, why it was added to DatoCMS, and learn how to use it through many real-world examples.

Let’s dive in!

## What Is Deep Filtering in DatoCMS?

[Deep filtering](https://www.datocms.com/docs/content-delivery-api/deep-filtering.md) is a feature of the Content Delivery API that allows you to filter records based on the content of their blocks. If you are not familiar with this concept, in [DatoCMS](https://www.datocms.com/docs/content-modelling/blocks.md) [blocks](https://www.datocms.com/docs/content-modelling/blocks.md) are data structures that users can embed in specific record fields. In other words, a block represents a sort of graphical component—such as a call to action, slider, and testimonial quote.

There are two types of block fields:

-   [**Structured Text**](https://www.datocms.com/docs/content-modelling/structured-text.md): A field type to create rich text content through a Notion-like editor (e.g., the rich text field of a blog post record).
-   [**Modular Content**](https://www.datocms.com/docs/content-modelling/modular-content.md): A special field type to define a dynamic area for richer page layouts (e.g. the design area field of a landing page record).
    

When a record has a Structured Text or Modular Content field, content creators can populate it with one or more blocks. Now, imagine you want to retrieve some records by the content of those fields. For example, you want to get only blog posts or landing pages that contain some specific information in a given block. Thanks to deep filtering, that is now possible!

In detail, deep filtering enables you to specify filtering conditions for blocks embedded in a Structured Text or Modular Content field. This new mechanism provides a simplified way to access the exact data you need without unnecessary additional API calls or application-level filtering operations. That means faster data retrieval, which results in improved server response time.

## How To Get Started With Deep Filtering

Follow the steps below and learn how to enable the deep filtering feature in your DatoCMS project.

### **Prerequisites**

Deep filtering works on a per-field basis. Specifically, you can enable it only on the Structured Text and Modular Content fields of a given model. Thus, your [content schema](https://www.datocms.com/docs/general-concepts/data-modelling.md) must involve some models with at least one field of one of those two types.

Assume you are building a blog application that only requires two models: Article and Landing page. You could define the Article model as follows:

(Image content)

The Article model

And the Landing Page model as:

(Image content)

The Landing Page model

Note that the two models involve a Structured Text and Modular Content field, respectively.

Keep in mind that DatoCMS allows you to specify which blocks content editors can embed in the field. If the field does not accept any block type, it will always be empty and GraphQL deep filters will not be applicable.

In this example, we will consider three block types: Call to Action, Hero, and Product. This is how they are defined:

(Image content)

The Call to Action block

(Image content)

The Hero block

(Image content)

The Product block

Summing up, the two prerequisites to enable deep filtering on a field are:

1.  It must be a Structured Text or Modular Content field.
    
2.  It must accept at least one block type.
    

### **Enable the Deep Filtering Feature on a Field**

Hover the Structured Text or Modular Content field and click the “Edit Field” button on the right:

(Image content)

Note the "Edit field" button on the right

The following modal will show up:

(Image content)

Note the first slider

To turn on the desired feature, toggle the “Enable deep filtering in GraphQL?” slider:

(Video content)

Enabling the deep filtering feature

Before clicking the “Save field” button, make sure the block field accepts at least one block type. Reach the “Validations” tab, and verify that there are a few blocks allowed for the field as in the Modular Content sample field below:

(Image content)

Note the allowed blocks

Great, you just enabled deep filtering! You can now employ the GraphQL deep filters to the Content Delivery API calls. Learn how in the next two chapters.

## Deep Filtering Applied To a Modular Content Field: Use Cases

Modular Content fields are ideal for defining records that require dynamic layouts. Some examples? Landing pages, case studies, and portfolio pages. In a website or web application, those are all key pages!

Learn how to filter those records with deep filtering through real-world GraphQL sample queries.

In the schema used in this blog post, the target model for this section is `landing_page`. In particular, the Modular Content field to apply deep filters on is `content`. The blocks supported by `content` are `call_to_action`, `hero`, and `product`.

### **Single Block Filtering**

Landing page records can involve more than one block. However, suppose you are interested in filtering them based on the content of blocks of a specific type only.

Use the query GraphQL below to get all `landing_page` instances that contain a `call_to_action` block whose `title` is equal to the “Discover all products!” string:

```graphql
query {
  allLandingPages(
    filter: {
      content: {
        any: { callToAction: { title: { eq: "Discover all products!" } } }
      }
    }
  ) {
    id
    title
  }
}
```

As you can see, when a field has deep filtering enabled, you can then specify an `any` object. This can contain a property for each block type that the field accepts. In these properties, you can add one or more filtering conditions [as explained in the documentation](https://www.datocms.com/docs/content-delivery-api/filtering-records.md). In other terms, the keyword `any` reads as “find records where any X/Y/Z block respects these conditions”.

That query would produce a result like this:

(Image content)

Out of all the landing pages available, it retrieved only the ones matching the specified filtering criteria.

Note that you can add more than one filtering condition. For example, you could look for all landing pages that have a `product` block whose `name` contains “Course” and `price` is lower than 50:

```graphql
query {
  allLandingPages(
    filter: {
      content: {
        any: {
          product: {
            name: { matches: { pattern: "Course" } }
            price: { lt: "50" }
          }
        }
      }
    }
  ) {
    id
    title
  }
}
```

This time, the result will be:

(Image content)

### **Multiple Block Filtering**

Block filtering is not limited to a single block but can applied to multiple block types.

Write the GraphQL query that follows to get all landing pages that have both a `hero` block with a “Join our TypeScript course!“ `title` and a `product` whose `price` is greater than 50:

```graphql
query {
  allLandingPages(
    filter: {
      content: {
        any: {
          hero: { title: { eq: "Join our TypeScript course!" } }
          product: { price: { gt: "50" } }
        }
      }
    }
  ) {
    id
    title
  }
}
```

To define specific filtering conditions on multiple blocks, all you have to do is specify more than one property in the `any` object. By default, DatoCMS enforces the AND operator between each.

The result will be:

(Image content)

For the [OR operator](https://www.datocms.com/docs/content-delivery-api/deep-filtering.md#putting-conditions-in-or), you need instead a different syntax. Now, you want to get all landing pages that have a `hero` block with the “Join our JavaScript course!“ `title` or a `product` block whose `price` is greater than 50. Achieve that with:

```graphql
query {
  allLandingPages(
    filter: {
      OR: [
        {
          content: {
            any: { hero: { title: { eq: "Join our JavaScript course!" } } }
          }
        }
        { content: {
          any: { product: { price: { gt: "50" } } } }
        }
      ]
    }
  ) {
    id
    title
  }
}
```

The new returned data will be:

(Image content)

This time, the result also contains the “Discounted JavaScript Course” landing page.

### **Block Presence Filtering**

Together with filtering on the content of blocks, you can also filter records based on the presence of at least one block with the [`exists`](https://www.datocms.com/docs/content-delivery-api/deep-filtering.md#filter-records-containing-at-least-one-block-of-any-kind) operator:

```graphql
query {
  allLandingPages(
    filter: {
      content: { exists: true }
    }
  ) {
    id
    title
  }
}
```

The above GraphQL query will return all landing pages that have at least one block:

(Image content)

If you are instead interested in the presence of a specified block type, you need to use the [`containsAny`](https://www.datocms.com/docs/content-delivery-api/deep-filtering.md#filter-records-containing-at-least-one-block-of-specified-type) operator:

```graphql
query {
  allLandingPages(
    filter: {
      content: {
        containsAny: { product: false, callToAction: true }
      }
    }
  ) {
    id
    title
  }
}
```

You will now get all landing pages that have a `call_to_action` block but have not a `product` block:

(Image content)

## Deep Filtering Records Based on a Structured Text Field: Use Cases

Structured Text is a versatile field type for defining rich textual content. DatoCMS provides some built-in elements, such as headers, code snippets, lists, and more, but you can also extend it to accept custom blocks.

In the schema used in this blog post, the target model for this section is `article`. In detail, the Structured Text field to apply deep filtering on is `content`. The only custom block supported by `content` is `call_to_action`:

(Image content)

Note the allowed blocks

See how to filter records with these types of fields via GraphQL deep filters.

### **Rich Text Content Filtering**

Before getting started, you need to know that the Content Delivery API already supports filtering records based on the content of a Structured Text field. Thus, you do not need deep filtering for that.

For example, you can get all blog posts that contain the word “JavaScript” or “TypeScript” with this GraphQL query:

```graphql
query {
  allArticles(
    filter: {
      content: {
        matches: { pattern: "(Java|Type)script" }
      }
    }
  ) {
    id
    title
    subtitle
  }
}
```

Notice the use of a complex pattern to implement the intended search strategy. That query will work like a charm:

(Image content)

However, that GraphQL query would no longer work when you enable deep filtering on the `content` field. You would get the following error:

(Image content)

Note the GraphQL schema error

Why? Because **deep filtering on a Structured Text field will cause a change to the associated GraphQL filter type!** After enabling it, the equivalent query will become:

```graphql
query {
  allArticles(
    filter: {
      content: {
        value: {
          matches: { pattern: "(Java|Type)script" }
        }
      }
    }
  ) {
    id
    title
    subtitle
  }
}
```

Basically, you just have to wrap `content` with the `value` object.

Et voilà! You’ll get the same result as before this time:

(Image content)

**Note**: None of these approaches will consider the content within the custom blocks. So, if an article does not contain the term “JavaScript” in the rich-text section but contains it in a `call_to_action` block, the queries will not return it.

### **Block Filtering**

Deep filtering on Structured Text gives you the ability to apply filtering conditions to custom blocks contained in the field as well. Specifically, you can use all deep filters that are valid for Modular Content fields.

This is how you can do it:

```graphql
query {
  allArticles(
    filter: {
      content: {
        blocks: {
          containsAny: { callToAction: true }
        },
        value: {
          matches: { pattern: "CMS" }
        }
      }
    }
  ) {
    id
    title
    subtitle
  }
}
```

The `blocks` object accepts filters as mentioned in the previous chapter. Those conditions will only be applied to the blocks contained in the field.

The above query will return all articles that contain the word “CMS” and has a `call_to_action` block:

(Image content)

Congrats! You are now a DatoCMS deep filtering master!

## Pros and Cons of Deep Filtering

Time to dig into the benefits and limitations of the feature.

**👍 Pros**:

-   **Enhanced filtering capabilities**: You can now retrieve records based on the content of their blocks.
-   **Granular control**: The deep filtering feature must be enabled on a per-field basis, so you are in control of when to use it.
    
-   **Intuitive GraphQL syntax**: Writing queries involving deep filters is intuitive and supported by the Explorer feature on the Content Delivery API Playground page.
-   **Many filtering options available**: All filtering conditions available for record filtering also work for deep record filtering.
    

**👎 Cons**:

-   **Breaking change in the GraphQL schema with Structured Text fields**: Enabling deep filtering on Structured Text fields leads to breaking changes in the existing GraphQL schema. So, before enabling it in your primary environment, test it on a sandbox environment.
-   **No nested filtering**: As of this writing, deep filtering is limited to one level of depth. That is, you cannot filter records by the content of blocks nested inside other blocks of a field.
    

## Conclusion

In this article, you dug into the deep filtering feature supported by the DatoCMS Content Delivery API. In particular, you understood that it enables you to filter records based on the content within their blocks.

You now know:

-   What deep filtering is.
-   How it works.
    
-   How to enable it on a Structured Text or Modular Content field.
-   How to use it in different scenarios.
    

DatoCMS keeps improving and the list of features gets longer every month. Want to give it a try? [Sign up for free today](https://dashboard.datocms.com/signup) and get your hands on one of the most feature-rich headless CMSs on the market!

Thanks for reading! We hope that you found this article helpful. Feel free to [reach out to us](https://www.datocms.com/support.md) with any questions, comments, or suggestions. Consider also joining our [community on Slack](https://www.datocms.com/slack.md).