How to Filter Query Results by a Property that is a Reference

3 replies
Last updated: Sep 7, 2020
Hi, I was wondering how I could filter query results by a property that is a reference? i.e. i have X amount of “downloads” and want to filter them by a given “tag”. “tags” is an array of references.
AI Update

To filter query results by a reference property (like filtering "downloads" by a given "tag" where tags is an array of references), you'll want to use filtering within array projections using the @ operator (parent scope operator).

Here's the pattern that works:

*[_type == 'downloads']{
  'tags': tags[(@->someProperty == someValue)]->
}[length(tags) > 0]

For your specific case, if you want to filter downloads that have at least one tag matching certain criteria:

*[_type == 'downloads']{
  'tags': tags[(@->_id == "specific-tag-id")]->
}[length(tags) > 0]

The key parts here:

  1. tags[(@->someProperty == condition)] - This filters the array of references inline. The @ refers to the current item in the array, and -> dereferences it to access properties of the referenced document.

  2. [length(tags) > 0] - This final filter ensures you only get documents where at least one tag matched your criteria.

You can also add multiple conditions:

*[_type == 'downloads']{
  'matchingTags': tags[(@->active == true && @->category == "featured")]->
}[length(matchingTags) > 0]

Important: This syntax requires API version v2021-03-25 or later. Make sure your query client is configured to use this version:

const client = sanityClient({
  // ... other config
  apiVersion: '2021-03-25'
})

This approach is much more efficient than fetching all documents and filtering client-side, as the filtering happens at the query level in the Content Lake.

This could be it:
*[_type=="tag" && title == $tag]{
  title,
  "downloads": *[_type=='download' && references(^._id)] {
  	title
  }
}

If you have a document called, for example:
toFilter
that references a set of
tags
that you want to filter by, you could do the following:

*[_type=="toFilter"] {..., tags-> } [tags.name ==$nameOfTagToFilterBy] 
This uses the ability of GROQ to chain arbitrarily many
[ ]
( filter-by truth-value of contents ) and
{}
( get these properties from the result-set ), by first getting every document of type
toFilter
(
*[ _type == "toFilter]
), then expanding the references while keeping every field (
{ ..., tags->}
) and then filtering the resulting array of documents by properties on the now expanded tag-field (
[tags.name == $nameOfTagToFilterBy]
).
Note the difference between
*[]
and
[]
here. The
*[]
means “give me EVERY document, and then filter by them by the contents of my
[]
“, while
[]
alone means “for the documents I already have from prior filters, filter them further by these contents”.
Does that help?
🙂
really helpful, thanks
user C

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?