GROQ: Filter documents by matching references in two arrays

12 replies
Last updated: Jan 27, 2026
I have a GROQ question about getting references from an arrays that are included in another array, if that is possible.

Field and document names has been altered for simplicityI currently have a document called Tag, its only field is a string.
My second doucument (
article) has an array of reference to Tag (tags) - these are tags for this documentMy third document (
articleList) is meant to list articles with certain tags. So this document also has an array of references to Tag (articleTags)
I've tried different versions of this query but they all give me either zero results or an error:
This for instance gives:
No function in() defined for arguments (array, array)

// just query the first (and only) article list
*[_type == 'articleList'][0] {
  "articlesToShow": *[_type == 'article' && tags[]._ref in ^.articleTags[]._ref]
}
If instead only let an
article have one tag (tag) instead of multiple, the following query works. But in real life, most articles would need more than one tag:
// just query the first (and only) article list
*[_type == 'articleList'][0] {
  "articlesToShow": *[_type == 'article' && tag._ref in ^.articleTags[]._ref]
}
Any thoughts?
AI Update

You're running into the classic GROQ challenge of checking if any element in one array matches any element in another array! The error No function in() defined for arguments (array, array) happens because the in operator can't directly compare two arrays.

The solution is to use the count() + @ pattern to check for array overlap. Here's how to fix your query:

*[_type == 'articleList'][0] {
  "articlesToShow": *[
    _type == 'article' 
    && count(tags[]._ref[@ in ^.articleTags[]._ref]) > 0
  ]
}

How this works:

  1. tags[]._ref projects your article's tag references into a simple array like ["tag1", "tag2"]
  2. The [@ in ^.articleTags[]._ref] filters this array to only elements that exist in the parent's articleTags
  3. count(...) counts how many matches there are
  4. > 0 means "at least one tag matches"

The ^ operator accesses the parent scope (your articleList document) from within the subquery.

Alternative approach if you want it more explicit:

*[_type == 'articleList'][0] {
  articleTags,
  "articlesToShow": *[
    _type == 'article' 
    && count(tags[@._ref in ^.^.articleTags[]._ref]) > 0
  ]
}

Note the double ^.^. - this is because tags[query] creates its own closure, so you need to go up two levels to reach the articleList document.

This pattern is one of the trickier parts of GROQ, but it's super powerful once you get the hang of it! The community thread I found shows several examples of this technique in action, including a detailed breakdown for matching related posts by tags.

Show original thread
12 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.

Was this answer helpful?