How to efficiently query and group Sanity articles by category?

4 replies
Last updated: Jul 25, 2022
hello there.. i have a main index page which is going to display articles that are written in sanity studio. i want to display articles by category. will i need to call separate queries for each category just to separate the articles out or is there a better way of doing it to avoid 4+ separate queries per page load?
AI Update

Great question! You definitely don't need to make separate queries for each category. There's a much better approach that lets you fetch all articles in a single query and then group them by category on the client side.

The most efficient pattern is to fetch all articles once with their category information, then group them in your application code. Here's how:

*[_type == "article"] {
  _id,
  title,
  slug,
  category->{
    _id,
    title
  }
}

This single query gets all your articles with their category references resolved. Then in your JavaScript/TypeScript code, you can group them:

const articlesByCategory = articles.reduce((acc, article) => {
  const categoryId = article.category._id;
  if (!acc[categoryId]) {
    acc[categoryId] = {
      category: article.category,
      articles: []
    };
  }
  acc[categoryId].articles.push(article);
  return acc;
}, {});

Why this is better:

  1. Single network request - Much faster than 4+ separate queries
  2. Better caching - CDN can cache one response instead of multiple
  3. More efficient - The query engine processes one query plan instead of several

If you have a massive number of articles and need to optimize further, you could add filtering or pagination to the initial query, but for most use cases, fetching all articles and grouping client-side will be the fastest and simplest approach.

The key insight from GROQ query optimization best practices is that moving logic to a single efficient query is almost always better than multiple queries, and client-side grouping is essentially free compared to network overhead.

Show original thread
4 replies
You could do a single query with one to four subqueries, too (either treating them collectively like an array or busting them out for granular changes).
I would query the categories themselves that match the category document type, and then do a projection inside them called something like "posts" that is another query referencing the "parent" category.

Part of the reason is, you may run into situations where you want them to do mostly the same thing but treat them differently (e.g. you need ten total but want to make sure no more than 4 come from Category B)

Alternately, you could also query all posts matching those categories but I'd be worried it's literally grabbing all of them first under the hood before filtering. I try to think general to specific.

If I couldn't make the query itself work, I'd leave it to my language of choice fetching the data to map them out and sort them.

It's not a focus of my talk Wednesday but in the project I'll be discussing I needed to do that at one point; I had a date field for magazine publication dates and developed an array of years from every doc, boiling it down to uniques. Then, whenever the year in the doc matched the array key, in it went, like mugs in a cupboard.

Side note that the
groq channel is well-suited to ask too, just because they're so fluent and clever. I personally have to pseudocode the queries first to understand what I am trying to do haha πŸ˜ƒ
thanks! yeah i cant cound how many times i have used console.log to see what im doing. it helps a lot! I will just grab all the articles for now and manipulate it myself for now thanks for the help!
In another doc type for departments for career opportunities, I am using the ordering plugin to sort them, and each contains a list of open job positions. That way it "goes into the camera" already in the order I'd like, and is pre-selected.
Probably a lot of work for posts (unless it was a means of treating it like 'featured' posts' but that's a much more concise and efficient query with just a smidge more manual work and then no more elbow grease in the code.
Oh yay, I am pleased with myself that I sort of had the right idea -- I just saw
user L
respond in the other channel πŸ˜ƒ Editing the top of my initial response for posterity.

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?