Filter array of references by field value in same document

10 replies
Last updated: Jan 17, 2024
Hey y’all. Could someone point me to some documentation on how to filter an array of references based on field in the same document? I am working on a portfolio and want to be able to create groups of projects based on a field found in the project. For example, each project has an
Area
field that could be one of a pre-defined list of options (Visual Communication, Product Design, Environmental Design, etc). As I am building my pages, I’d like to have the ability to add choose an
Area
option prior to creating a
Project Group
so that when I go to add projects to the group, I am only given the projects with that field.Thanks in advance.
AI Update

You're looking for how to filter reference options based on a field in the current document - this is definitely possible! You'll want to use the options.filter function on your reference field.

Here's how to set this up for your portfolio use case:

{
  name: 'projectGroup',
  type: 'document',
  fields: [
    {
      name: 'area',
      type: 'string',
      title: 'Area',
      options: {
        list: [
          {title: 'Visual Communication', value: 'visual'},
          {title: 'Product Design', value: 'product'},
          {title: 'Environmental Design', value: 'environmental'}
        ]
      }
    },
    {
      name: 'projects',
      type: 'array',
      of: [
        {
          type: 'reference',
          to: [{type: 'project'}],
          options: {
            filter: ({document}) => {
              // Only show projects that match the selected area
              if (!document.area) {
                return {
                  filter: 'area == $area',
                  params: {area: null} // or show all if no area selected
                }
              }
              return {
                filter: 'area == $area',
                params: {area: document.area}
              }
            }
          }
        }
      ]
    }
  ]
}

The options.filter function receives an object with properties like document, parent, and value, and returns an object with:

  • filter: A GROQ filter string
  • params: Parameters to use in the filter (helps prevent injection issues)

So in your case, when you select "Visual Communication" in the area field, only projects with area == 'visual' will appear when you go to add references to the projects array.

You could also combine this with conditional fields if you wanted to hide the projects field entirely until an area is selected:

{
  name: 'projects',
  type: 'array',
  hidden: ({document}) => !document?.area,
  // ... rest of config
}

This pattern works great for creating filtered, contextual editing experiences where you're building relationships between documents based on shared taxonomy or categorization fields!

Show original thread
10 replies
so in plain english you want to group posts by whether or not a post has a field set correct? so probably want the Defined GROQ function
not sure I understand this bit though
I’d like to have the ability to add choose an
Area
option prior to creating a
Project Group
so that when I go to add projects to the group, I am only given the projects with that field.
oh ok you want to filter the array reference at runtime when you make a choice?
Correct. Thanks for the translation.:)
here is the docs around filtering : https://www.sanity.io/docs/reference-type#filter-ebd7a95f9dc6
and here is a post someone replied to that has what you need I believe:
https://www.sanity.io/answers/filtering-reference-based-on-selected-product
you basically need to use the
document
object to find the field value you want to filter the references by.
Fantastic! Thanks for the help.
Thanks again for your help, but I can’t seem to make this work. Using the
document
as a starting point to locate the field I need seems a long way to go to get the value I need. And
parent
does get me up the level I need. How would I get to the field
designArea
with the local object?
import React from 'react';

export default {
  name: 'projectGroup',
  title: 'Project Group',
  type: 'object',
  initialValue: {
    disabled: false,
  },
  fields: [
    {
      name: 'designArea',
      title: 'Design Area',
      type: 'designArea',
    },
    {
      name: 'content',
      title: 'Projects',
      description: 'Choose from our projects.',
      type: 'array',
      of: [
        {
          type: 'reference',
          to: [{ type: 'project' }],
          options: {
            filter: ({ document }) => {
              // Get value of designArea, if any
              if (!document.designArea) {
                // If no designArea has been set…
                return {
                  filter: 'visibility == $visibility',
                  params: { visibility: true },
                };
              }
              // If designArea has been set…
              return {
                filter: 'visibility == $visibility && area == $designArea',
                params: {visibility: true, designArea: document.designArea}
              }
            },
          },
        },
      ],
      validation: (Rule) => Rule.max(12),
    },
    {
      name: 'disabled',
      title: 'Disable?',
      type: 'boolean',
    },
  ],
  preview: {
    select: {
      disabled: 'disabled',
      project0: 'projects.0.title',
      project1: 'projects.1.title',
      project2: 'projects.2.title',
      project3: 'projects.3.title',
    },
    prepare: ({ disabled, project0, project1, project2, project3 }) => {
      const projects = [project0, project1, project2].filter(Boolean);
      const subtitle = projects.length > 0 ? projects.join(', ') : '';
      const hasMoreProjects = Boolean(project3);
      return {
        title: `Project Group`,
        subtitle: hasMoreProjects ? `${subtitle}…` : subtitle,
        media: (
          <span style={{ fontSize: '1.5rem' }}>
            {disabled || disabled == null ? ':skull:' : ':white_check_mark:'}
          </span>
        ),
      };
    },
  },
};
Yup! Got it sorted out. Thanks for the reply though!
Great!

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?