Advanced Data Retrieval With Deep Filtering in DatoCMS

Advanced Data Retrieval With Deep Filtering in DatoCMS

Posted on December 19th, 2023 by Antonello Zanini

The introduction of deep filtering 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 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 blocks 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: 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: 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 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:

The Article model

And the Landing Page model as:

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:

The Call to Action block
The Hero block
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:

Note the "Edit field" button on the right

The following modal will show up:

Note the first slider

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

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:

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_actionhero, 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:

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. 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:

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:

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

This time, the result will be:

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:

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:

For the OR operator, 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:

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:

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 operator:

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

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

If you are instead interested in the presence of a specified block type, you need to use the containsAny operator:

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:

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:

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:

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:

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

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:

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:

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:

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:

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 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 with any questions, comments, or suggestions. Consider also joining our community on Slack.