GROQ: Filter posts by category when categories is an array field
export default {
name: 'post',
title: 'Post',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96,
},
},
{
name: 'author',
title: 'Author',
type: 'reference',
to: {type: 'author'},
},
{
name: 'mainImage',
title: 'Main image',
type: 'image',
options: {
hotspot: true,
},
},
{
name: 'categories',
title: 'Categories',
type: 'array',
of: [{type: 'reference', to: {type: 'category'}}],
},
{
name: 'publishedAt',
title: 'Published at',
type: 'datetime',
},
{
name: 'body',
title: 'Body',
type: 'blockContent',
},
],
preview: {
select: {
title: 'title',
author: 'author.name',
media: 'mainImage',
},
prepare(selection) {
const {author} = selection
return Object.assign({}, selection, {
subtitle: author && `by ${author}`,
})
},
},
}When filtering posts by a category field that's an array of references in GROQ, you have several options depending on what you're trying to achieve:
Basic Array Filtering
To check if a specific category reference exists in the array:
*[_type == "post" && "category-id-here" in categories[]._ref]This checks if the category ID appears in the _ref field of any item in the categories array.
Filter by Category Slug
If you want to filter by a category's slug (after dereferencing):
*[_type == "post" && "my-category-slug" in categories[]->slug.current]The -> operator dereferences each category reference and lets you access its properties.
Filter by Multiple Categories (OR)
To find posts that have any of several categories:
*[_type == "post" && count((categories[]._ref)[@ in ["cat-id-1", "cat-id-2"]]) > 0]Or with slugs:
*[_type == "post" && count((categories[]->slug.current)[@ in ["action", "thriller"]]) > 0]Filter by Multiple Categories (AND)
To find posts that have all of the specified categories:
*[_type == "post" && count((categories[]->slug.current)[@ in ["action", "thriller"]]) == 2]Just adjust the == 2 to match the number of categories you're requiring.
Using the references() Function
For a cleaner syntax when checking a single category:
*[_type == "post" && references("category-id-here")]This checks if the document references the specified ID anywhere in its reference fields.
The key thing to remember is that categories[]._ref gives you an array of the referenced IDs, and you can use the in operator or count() function to check membership. The -> operator is super handy for accessing properties of the referenced documents directly in your query.
Show original thread6 replies
Was this answer helpful?
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.