πŸ‘€ Our most exciting product launch yet πŸš€ Join us May 8th for Sanity Connect

Filter Content by Multiple Tags

By David Witt

Search documents that are tagged with at least one of these tag slugs

Filter Book Resources

*[count((tags[]->slug.current)[@ in ["nonfiction", "fiction"]]) > 0 && _type == "resource"] {
  ...
}

Schema Files for Resource and Tag

export const tagSanityDefinition = defineType({
  name: "tag",
  title: "Tag",
  type: "document",
  icon: TagIcon,
  fields: [
    defineField({
      name: "title",
      title: "Title",
      type: "string",
      validation: (Rule) => Rule.required(),
    }),
    defineField({
      name: "slug",
      title: "Slug",
      type: "slug",
      options: {
        source: "title",
        maxLength: 96,
      },
      validation: (Rule) => Rule.required(),
    }),
    defineField({
      name: "description",
      title: "Description",
      type: "text",
      validation: (Rule) => Rule.required(),
    }),
  ],
});

export const resourceSanityDefinition = defineType({
  name: "resource",
  title: "Resource",
  type: "document",
  fields: [
    defineField({
      name: "title",
      title: "Title",
      type: "string",
      validation: (Rule) => Rule.required(),
    }),
    defineField({
      name: "slug",
      title: "Slug",
      type: "slug",
      options: {
        source: "title",
        maxLength: 96,
      },
      validation: (Rule) => Rule.required(),
    }),
    defineField({
      name: "description",
      title: "Description",
      type: "text",
      validation: (Rule) => Rule.required(),
    }),
    defineField({
      name: "tags",
      title: "Tags",
      description: "Tags help make resources easier to find by search",
      type: "array",
      of: [{ type: "reference", to: { type: "tag" } }],
    }),
  ],
});

Tags are a great way to categorize content in a loose structure. When you want to filter content by a single tag, GROQ is relatively straightforward.

It's a bit trickier to filter by one or more tags. In this example, I have several Resources that are books, and each book is tagged as fiction or nonfiction. I want to show all my books: resources with a tag of fiction or nonfiction:

count((tags[]->slug.current)[@ in ["nonfiction", "fiction"]]) > 0

Starting from the outside: count() > 0 will query for content where the inside query result is > 0.

Inside the count query: tags[]->slug.current gets the tags for all documents, then dereferences each tag so we have the slug value.

@ refers to the root value. In this case, the root value is the current tag slug.

Combining together will result in all documents tagged with "fiction" or "nonfiction"

If you'd like the change the logic to include all tags in the array, you can adjust your outer count function like this:

*[count((tags[]->slug.current)[@ in ["react", "remix"]]) == 2 && _type == "resource"] {
...
}

Contributor

Other schemas by author