Filter array to exclude already referenced sections in Sanity document
primary
primaryis an array of
itemobjects.In item, instead of getting a list of all sections, I only want to see those which are not already referenced by my document.
Maybe this is actually very simple, but I canât seem to work it outâŚ
name: 'item',
title: 'Item',
type: 'object',
fields: [
{
name: 'section',
title: 'Section',
type: 'reference',
to: { type: 'section' },
options: {
filter: ({ document, parent, parentPath }) => {
console.log(document._id)
return {
filter: '!(^._id in *[_id==$document].primary[])',
params: {
document: document._id
}
}
}
}
}
]I can help you filter out already-referenced sections from your reference field! The issue with your current query is the syntax - you're trying to access the parent document's array, but the approach needs adjustment.
Here's the corrected solution:
{
name: 'section',
title: 'Section',
type: 'reference',
to: { type: 'section' },
options: {
filter: ({ document }) => {
// Get all section IDs already referenced in the primary array
const referencedIds = document.primary
?.map(item => item.section?._ref)
.filter(Boolean) || []
return {
filter: '!(_id in $referencedIds)',
params: {
referencedIds
}
}
}
}
}What's happening here:
Extract referenced IDs in JavaScript: Instead of trying to do this purely in GROQ, we extract the
_refvalues from theprimaryarray items in the filter function itself. This is more reliable since you have direct access to the document object.Simple GROQ filter: The GROQ filter
!(_id in $referencedIds)checks if the current section's_idis NOT in the array of already-referenced IDs.Pass as params: We pass the array of IDs as a parameter to the GROQ query.
Important note: The filter function re-runs when the document changes, so as you add sections to your primary array, they'll automatically disappear from the available options in other items.
Making it reusable:
You can extract this into a utility function to keep your code DRY, as shown in this community example:
// utils/getFilter.js
export const getFilter = (document, field, refField = '_ref') => {
const existingEntries = document[field]
?.map(item => item[refField])
.filter(Boolean) || []
return {
filter: '!(_id in $existingEntries)',
params: {
existingEntries
}
}
}
// Then in your schema:
options: {
filter: ({ document }) => {
const referencedIds = document.primary
?.map(item => item.section?._ref)
.filter(Boolean) || []
return {
filter: '!(_id in $referencedIds)',
params: { referencedIds }
}
}
}This is a common pattern when building navigation menus, related content pickers, or any scenario where you want to avoid duplicate references in an array!
Show original thread26 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.