How to paginate GROQ query with filtered author reference in blog posts

8 replies
Last updated: May 9, 2022
Hello, I’m looking for some help with my groq query. I’m trying to paginate a search for blog posts (type) filtered by author value (slug or name) and am unsure how to do so because I can’t seem to expand that reference in the initial filter.
More in comments…
AI Update

I can help you with filtering and paginating blog posts by author reference! This is a common challenge in GROQ because you need to filter by a referenced document's field before expanding the reference.

The key is to use the dereferencing operator (->) directly in your filter, not just in the projection. Here's how to structure your query:

*[_type == "post" && author->slug.current == "author-slug-here"] | order(publishedAt desc) [0...10] {
  _id,
  title,
  publishedAt,
  author-> {
    name,
    slug
  }
}

Or if you want to filter by author name:

*[_type == "post" && author->name == "John Doe"] | order(publishedAt desc) [0...10] {
  _id,
  title,
  publishedAt,
  author-> {
    name,
    slug
  }
}

Key points:

  1. Filter with dereference: Use author->slug.current or author->name directly in your filter condition. This tells GROQ to follow the reference during filtering.

  2. Pagination: The [0...10] slice gives you the first 10 results. For subsequent pages, use [10...20], [20...30], etc.

  3. Expand in projection: You can still expand the full author reference in your projection using author-> { ... } to get all the author fields you need.

If you need more efficient pagination for large datasets, consider using a cursor-based approach, which uses the last document's value as a starting point rather than array slicing:

*[_type == "post" && author->slug.current == "author-slug-here" && publishedAt < $lastPublishedAt] 
  | order(publishedAt desc) [0...10]

This approach performs better at scale because it doesn't need to skip over all previous results—you just pass in the publishedAt value from the last item of the previous page as the $lastPublishedAt parameter.

Show original thread
8 replies
I did create this query which worked, for initial data, but now I need to paginate.

*[_type == "author" && slug.current == $slug][0]{
  name,  
  "blogs": *[_type == "blog" && author._ref == ^._id] | order(_createdAt desc){
    _id,
    title,
    "slug": slug.current,
    "heroImage": heroImage{
        alt,
        "url": asset->
    },
    "author": author->{
        name,
        "slug": slug.current
    },
    "tags": tags[]->{
        _id,
        title,
        "slug": slug.current
    }
  }
}
I don’t think I can paginate because the value would need to be passed through a template literal.
I had been using template literals as my projection like so
*[_type == "author" && slug.current == $slug][0]{${myProjectionHere}]

But because I am passing a parameter down to the projection, I just went with a regular string
export async function getAuthorPageBySlug(slug, {count}) {
  const results = await sanityClient.fetch(
    `
    *[_type == "author" && slug.current == $slug][0]{
      name,
      "slug": slug.current,
      "blogs": *[_type == "blog" && author._ref == ^._id] | order(_createdAt desc)[${count}...${count + 6}] {
        _id,
        title,
        "slug": slug.current,
        "heroImage": heroImage{
            alt,
            "url": asset->
        },
        "author": author->{
            name,
            "slug": slug.current
        },
        "tags": tags[]->{
            _id,
            title,
            "slug": slug.current
        }
      }
    }
    `,
    { slug }
  );
  return results;
}
Hi Dani. Are you getting any errors or just no results?
Hey Geoff, I did eventually sort it out. I was trying to use template literals and was struggling since that would involve props and probably tagged template literals. I instead just went with a basic string
Thanks for following up. Glad to hear you got it working. 🎉
ace

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?