GROQ: Query articles grouped by tags from list component in single query

5 replies
Last updated: Oct 24, 2022
Hi Sanity Team! I need some help with a GROQ query…Let’s say I have a list component that displays articles and has an array of tags to switch between articles that are associated with that tag.

Would it be possible to get all the articles that are associated with each tag, in one query?

Something like:
*[_type == “list_component” && _id=“dsf”] {tags} {
//“tagName”: *[_type == “article” && references(tagId)]
}

I’d like to end with a result that looks something like this:
{
Tag1: [Array of articles associated with this tag],
Tag2: [Array of articles associated with this tag],

TagN: [Array of articles associated with this tag]
}

Currently, I have one query to get the tags from my list component. Then I have another query that gets the articles that reference each tag, but I would like to have it all in one query.

Thanks in advance! and sorry if my question isn’t very clear
😅
AI Update

Yes, absolutely! You can fetch all articles associated with each tag in a single GROQ query. The key is to use a projection that iterates over your tags array and fetches the related articles for each tag.

Here's how you can structure your query:

*[_type == "list_component" && _id == "dsf"][0] {
  tags[]{
    ...,
    "articles": *[_type == "article" && references(^._id)]
  }
}

Or if you want a cleaner structure with the tag as a key:

*[_type == "list_component" && _id == "dsf"][0] {
  "taggedArticles": tags[]{
    "tagName": name,
    "tagId": _id,
    "articles": *[_type == "article" && references(^._id)]
  }
}

How it works:

  • tags[] iterates over each tag in your tags array
  • ^._id uses the parent reference operator to refer back to the tag's _id in the enclosing scope
  • *[_type == "article" && references(^._id)] finds all articles that reference the current tag
  • The [0] after the first filter ensures you get a single object instead of an array

If your tags are stored as references (not inline objects), you might need to dereference them first:

*[_type == "list_component" && _id == "dsf"][0] {
  "taggedArticles": tags[]-> {
    "tagName": name,
    "tagId": _id,
    "articles": *[_type == "article" && references(^._id)]
  }
}

This gives you exactly what you're looking for - all tags with their associated articles in a single query! The ^ operator is the key here, allowing you to reference the parent tag's ID from within the nested query.

Show original thread
5 replies
GROQ seems to need the leftmost (or solo) "keys" to be either string literals representing a value, or existing fields/docs.
Someone asked last night about grouping by date and I was going to use string::startsWith and string::split to peel off the year at the front of the date in an experiment, but you can't have pure text and try to "project" off it, like little 'for' loops.

I'd love it if you could, but I get why you can't.

Something like

["2022", "2021"] {

"postsFromThisYear" : *[_type=="post" && year==^]

}

You might try moving this particular question to the
groq channel as there are some clever folks, including at least one of the GROQ devs himself, who might be able to cook something up.
I was afraid that might be the case… But yeah I’ll ask this again in groq and see if I can get any luck there. Thanks!
You should be able to do something like this:
*[_type == "list_component" && _id="dsf"].tags[]{
  tagName, //or whatever field contains the name of the tag
  "relatedArticles": *[_type == "article" && references(^._id)]
}
This is exactly what I wanted, thank you!
You're welcome!

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?