GROQ: Filter posts by category when categories is an array field

6 replies
Last updated: Jun 29, 2021
For GROQ queries how do you filter posts by category if its an array
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}`,
      })
    },
  },
}
AI Update

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 thread
6 replies
so when I do it like this it doesn't work
*[_type == "post" && 'Paintings' in categories[]->name] {
        title,
        slug,
        mainImage{
          asset->{
          _id,
          url
        }
      },
			categories
}
This is what the category data looks like when I just query all posts
{
  "categories": [
    {
      "_key": "1d8df8bf7a3a",
      "_ref": "49a70477-bf23-4d65-a0da-e84608fb7a40",
      "_type": "reference"
    }
  ],
  "mainImage": {
    "asset": {
      "_id": "image-37ac1ca3329a254d9de6b2b3a85b8e45444ac4b8-2712x3511-jpg",
      "url": "<https://cdn.sanity.io/images/7hxv42mc/production/37ac1ca3329a254d9de6b2b3a85b8e45444ac4b8-2712x3511.jpg>"
    }
  },
  "slug": {
    "_type": "slug",
    "current": "donnie-s-gullah-fruit-cart"
  },
  "title": "Donnie's Gullah Fruit Cart"
}
what is an example of
*[_type == "post"] {
  categories[]->
}
in your dataset?
what is an example of
*[_type == "post"] {categories[]->
}
Ahh so its title and not name! I was able to successfully query by category now. Thank you so much I was getting so frustrated &gt;_&lt;
Awesome!

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.

Was this answer helpful?