Unlock seamless workflows and faster delivery with our latest releases - Join the deep dive

GROQ query for getting references from arrays in another array in Sanity.io

12 replies
Last updated: Apr 9, 2020
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?
Apr 9, 2020, 9:32 AM
If you want to have tag x OR tag y, you need to write mulitple `in`s. Here’s a simplified example:
const tags = ['tag1', 'tag2']
const query = `*[_type == 'article' && (${tags.map(t => `'${t}' in tags`).join(' || ')})]`
Hope that helps!
Apr 9, 2020, 10:48 AM
Thank you. That didn't help though, feel in this case that I might need something more than a simplified example.Didn't even know that what looks like a js map and arrow function was possible in GROQ
🙂
Tried above code with some modifications but received error on

Param $ referenced, but not provided
Removing the first $ gives me:

String literal expected
Apr 9, 2020, 11:08 AM
Hi (Removed Name), could you share your code for the query? Looks like it might be an issue with backticks, brackets or something similar (or not having imported React).
As an alternative, you could also try this to go around the issue:

...
'articlesToShow': *[_type == 'article' && references(^.tags[]._ref)]
...
Apr 9, 2020, 11:23 AM
Here is the same but the tag string extracted to a variable, with how the query will end up looking like:
const tags = ['tag1', 'tag2']
const tagString = tags.map(t => `'${t}' in tags`).join(' || ')
// Output: 'tag1' in tags || 'tag2' in tags
const query = `*[_type == 'article' && (${tagString})]`
// Output: `*[_type == 'article' && ('tag1' in tags || 'tag2' in tags)]`
But what (Removed Name) said might be more what you’re looking for
👆
Apr 9, 2020, 11:31 AM
I was so into just writing GROQ that I didn't realise your suggestion (Removed Name) seems to be to compose the query using js and then finally just executing that last line, am I correct in my assumption?
My idea is simply to make one request if that is possible:
Query for "the current document" and join documents by making some sort of subquery.
Apr 9, 2020, 11:39 AM
So here are the three schemas in play, and an explanation at the end
Tag document

export default {
  name: 'tag',
  type: 'document',
  title: 'Tag',
  fields: [
    {
      name: 'title',
      type: 'string',
      title: 'Title'
    }
  ]
}
article doument

export default {
  name: 'article',
  type: 'document',
  title: 'Article',
  fields: [
    {
      name: 'title',
      type: 'string',
      title: 'Title'
    },
    {
      name: 'tags',
      type: 'array',
      title: 'Tags',
      type: 'array',
      of: [
        {
          type: 'reference',
          to: [{ type: 'tag' }]
        }
      ]
    }
  ]
}
article list document

export default {
  name: 'articleList',
  type: 'document',
  title: 'List of articles',
  fields: [
    {
      name: 'title',
      type: 'string',
      title: 'Title'
    },
    {
      name: 'articlesToShow',
      type: 'array',
      title: 'Show articles with the following tags',
      of: [
        {
          type: 'reference',
          to: [{ type: 'tag' }],
        },
      ],
    }
  ]
}

When querying for the article list, I would also like to query for the articles that are tagged with any of the tags that the current article list is tagged with.

Might be a better way to do this though..
Apr 9, 2020, 11:42 AM
So basically. Given the schemas above, the following GROQ would yield all articles tagged with the first articlesToShow tag:

*[_type == 'articleList'][]{
  'taggedArticles': *[_type == 'article' && tags[0]._ref in ^.articlesToShow[]._ref]
}
This would then work, giving me all articles tagged with the tags that the articleList has, but it feels kinda strange having to specify indices like this. It also creates a limit on how many tags we can support:


*[_type == 'articleList'][]{
  'taggedArticles': *[
     _type == 'article'
     && tags[0]._ref in ^.articlesToShow[]._ref
  	 || tags[1]._ref in ^.articlesToShow[]._ref
  	 || tags[2]._ref in ^.articlesToShow[]._ref
	]
}

Apr 9, 2020, 12:18 PM
Indeed, this approach should give you what you need but as you said, it can get a bit lengthy unless you query multiple times and implement what (Removed Name) suggested earlier. Have you tried the alternative query I posted above? 🙂
...
'articlesToShow': *[_type == 'article' && references(^.tags[]._ref)]
...
Apr 9, 2020, 1:17 PM
Yes I tried you solution but it didn't yield any results. Assuming it is because the tags-field references other tag-documents rather than articles
Apr 9, 2020, 1:20 PM
Looks like I missed
articlesToShow
— I assumed both arrays were called
tags
, sorry 🙂 Try this:
*[_type == 'articleList'] {
  'articlesToShow': *[_type == 'article' && references(^.articlesToShow[]._ref)]{
    title
  }
}
Apr 9, 2020, 1:33 PM
Thanks (Removed Name), that worked fine.A different take on the issue.
I must have seriously misunderstood how
references()
worked.. It seems to check (for each article I guess) if it references any of the articlesToShow refs?
Apr 9, 2020, 2:05 PM
That’s right, it checks for each article if it has
_ref
values from the
articlesToShow
array in its own references. These
_ref
values are essentially tag `_id`s, so a reference to the same tag will give the same
_ref
in
tags
,
articlesToShow
or any other field name you give to the array of references, as long as they all refer to the
tag
document type.
Apr 9, 2020, 2:18 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?