How to filter Sanity documents by referenced document's field value?
Good news - your approach is on the right track! GROQ does support filtering by referenced document fields, though the syntax needs a slight adjustment.
The issue with your second query is that you're trying to use a subquery directly inside the in operator. Instead, you need to construct an array of tag IDs first. Here are a few ways to accomplish this:
Option 1: Using a subquery with array construction
*[
_type == "article"
&& count((tags[]._ref)[@ in *[_type == 'tag' && slug.current in ['tag-a', 'tag-b']]._id]) > 0
]This checks if any of the article's tag references exist in the array of matching tag IDs.
Option 2: Using the -> dereference operator (Recommended)
This is often the cleanest approach - dereference the tags and filter on their properties directly:
*[
_type == "article"
&& "tag-a" in tags[]->slug.current
&& "tag-b" in tags[]->slug.current
]This dereferences each tag reference with -> and checks if the slug values match. Note that this requires both tags to be present (AND logic).
Option 3: For OR logic (articles with tag-a OR tag-b)
If you want articles that have either tag:
*[
_type == "article"
&& count(tags[]->slug.current[@ in ['tag-a', 'tag-b']]) > 0
]This dereferences the tags, gets their slugs, filters for matches, and checks if any exist.
The key insight is that the -> operator resolves references in the forward direction, letting you access fields on the referenced document directly. This is generally more readable and performant than constructing separate subqueries.
Keep in mind that dereferencing with -> does add some query complexity, but for most use cases the performance is perfectly acceptable. If you're working with very large datasets, you might want to check out query optimization techniques for additional performance improvements.
Show original thread9 replies
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.