
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeThe key to solving this is using the ^ caret operator in GROQ, which allows you to reference the parent scope. Here's how to fix your query:
*[_type == "tag"] {
title,
slug,
_id,
"postCount": count(*[_type == "post" && references(^._id)])
}[postCount > 0] | order(title asc)The ^ operator lets you access the current tag document from within the nested query. So ^._id refers to the _id of the tag you're currently iterating over.
Even better, you can use the references() function which is specifically designed for this use case. It checks if any document references the given document ID.
Here's a breakdown of what's happening:
*[_type == "tag"] - Get all tagspostCount fieldcount(*[_type == "post" && references(^._id)]) - Count posts that reference this tag's ID[postCount > 0] - Filter to only tags with at least one post| order(title asc) - Sort by titleThis approach is much cleaner than trying to match slug strings, and it works with Sanity's reference system directly. The references() function will check if the tag's _id appears in any reference field in the post documents (like your tags array).
If you specifically need to filter based on slug matching for some reason, you could do:
*[_type == "tag"] {
title,
slug,
_id,
"postCount": count(*[_type == "post" && ^.slug.current in tags[]->slug.current])
}[postCount > 0] | order(title asc)But the references() approach is more performant and idiomatic.
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store