How AI is powering better personalization in e-commerce [with Vercel]. Sign up now

GROQ query to get all authors from a specific publisher via book references

18 repliesLast updated: Nov 29, 2025

Hi all, I was wondering if I could get help with a specific type of query. In the following sample, I'm trying to get all the authors from a particular publisher but I can't figure out the exact GROQ syntax. Thanks much in advance!
Sample query:

*[_type == 'publisher' && code == 'PUB1']{
  authors: *[_type == 'author' && books[]->publisher._ref == ^._id]
}
Sample expected result (pseudocode):

"result" : [
  0: { 
    authors: [ author1, author2 ]
  }
]
Sample schema (pseudocode):

author:
  fields: [
    { name: 'books', type: 'array', of: [{ type: 'reference', to: [{ type: 'book' }] }] }
  ]

book:
  fields: [
    { name: 'publisher', type: 'reference', to: [{ type: 'publisher' }] }
  ]

publisher:
  fields: [
    { name: 'code', type: 'string' }
  ]
Sample data set (pseudocode):

sample set of authors:
  [
    {
      _id: 'author1',
      books: [
        { _ref: 'book1' },
        { _ref: 'book2' }
      ]
    },
    {
      _id: 'author2',
      books: [
        { _ref: 'book3' }
      ]
    },
    {
      _id: 'author3',
      books: [
        { _ref: 'book2' }
      ]
    }
  ]

sample set of books:
  [
    {
      _id: 'book1',
      publisher: { _ref: 'publisher1' }
    },
    {
      _id: 'book2',
      publisher: { _ref: 'publisher2' }
    },
    {
      _id: 'book3',
      publisher: { _ref: 'publisher1' }
    }
  ]

sample set of publishers:
  [
    {
      _id: 'publisher1',
      code: 'PUB1'
    },
    {
      _id: 'publisher2',
      code: 'PUB2'
    },
    {
      _id: 'publisher3',
      code: 'PUB3'
    },
  ]
AI Update

I can help you with this GROQ query! The issue is that you can't use a nested *[...] filter inside a projection like that. Instead, you need to query from the top level and use the parent scope operator (^) to reference the outer query's document.

Here's the corrected query:

*[_type == 'publisher' && code == 'PUB1']{
  "authors": *[_type == 'author' && references(^._id)]{
    _id,
    // include other author fields you need
  }
}

However, this uses the references() function which only works for direct references. Since your authors don't directly reference publishers (they reference books, which reference publishers), you need a different approach.

For your specific schema where the relationship is author -> books -> publisher, here's the working query:

*[_type == 'publisher' && code == 'PUB1']{
  "authors": *[_type == 'author' && count(books[]->publisher._ref match ^._id) > 0]
}

Or more efficiently using array filtering:

*[_type == 'publisher' && code == 'PUB1']{
  _id,
  "authors": *[_type == 'author' && ^._id in books[]->publisher._ref]
}

How this works:

This will return your expected result where each publisher has an authors array containing all authors who have written at least one book for that publisher.

Alternative approach - If you need more control over the author data or want to include additional fields from the books, you could also query from the author perspective:

*[_type == 'author' && 'publisher1' in books[]->publisher._ref]{
  _id,
  name,
  "relevantBooks": books[]->{
    _id,
    title,
    publisher->
  }[publisher.code == 'PUB1']
}

The key insight is that GROQ's reference access operator (->) allows you to traverse relationships, and the parent scope operator (^) lets you reference values from outer queries when building nested projections.

Show original thread
18 replies

Was this answer helpful?

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.

Related contributions