GROQ: Exclude already referenced documents from array reference field options
You're very close! The issue is that you need to pass the actual subServices array values to the GROQ filter as parameters. Here's the corrected version:
export const Service = defineType({
name: 'service',
title: 'Service',
type: 'document',
fields: [
defineField({
name: 'subServices',
title: 'Sub Services',
type: 'array',
of: [
{
type: 'reference',
to: [{ type: 'service' }],
options: {
filter: ({ document }) => {
const subServiceIds = (document.subServices || [])
.map(ref => ref._ref)
.filter(Boolean);
return {
filter: '!(_id in $subServiceIds)',
params: { subServiceIds }
}
}
}
}
],
})
]
})The key differences from your code:
- Extract the IDs: You need to map through
document.subServicesto get an array of_refvalues from the reference objects - Use parameters: Pass the array as a GROQ parameter (
$subServiceIds) rather than trying to reference the field directly in the query string - Handle undefined: Add the
|| []fallback andfilter(Boolean)to handle cases where the array doesn't exist yet or contains undefined values
The GROQ filter string !(_id in $subServiceIds) means "exclude documents whose _id is in the subServiceIds array", which is exactly what you want.
This pattern works because the filter function receives the current document state, allowing you to dynamically adjust what references are available based on what's already been selected. The dynamic filter will re-evaluate each time the subServices array changes, keeping the available options up to date.
Show original thread5 replies
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.