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

18 replies
Last updated: Dec 14, 2022
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:

  1. The outer query finds publishers with code == 'PUB1'
  2. The ^ operator references the current publisher document from the outer query
  3. books[]-> dereferences all book references in the author's books array
  4. books[]->publisher._ref gets the publisher reference from each book
  5. The in operator checks if the current publisher's _id appears in that array

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
Bumping up to see if I could get help here please. We've been stuck for a few days now. Thanks much in advance!
Here's an example of a working query for the data you shared.
Ah! Using
in
instead of
==
. I'll give it a shot. Sorry for the delayed response. Didn't see this until today. I'll give it a shot and report back. Thanks much as always
user M
!
user M
So I've got a weird thing going on. I tried applying this to the full dataset. If I explicitly use the _id (e.g., publisher1), it works, but when I use ^._id, the query returns an empty result. Any suggestions?
Works:

*[_type == 'publisher' && code == 'PUB1']{
  'authors': *[_type == 'author' && 'publisher1' in books[]->.publisher._ref]
}
Does not work:

*[_type == 'publisher' && code == 'PUB1']{
  'authors': *[_type == 'author' && ^._id in books[]->.publisher._ref]
}
Side note: I tried both
books[]->publisher
and
books[]->.publisher
with the same results.
Thanks much in advance!
Bumping up please.
user M
or anyone else who can help. Thanks much in advance!
What version of the API are you using?
2022-10-26
Morning
user M
! Sorry for pressing, bumping to the top as the project that this is for is getting pushed harder for completion this week and this is the last piece in our puzzle. Thanks much in advance!
I'll need significantly more information to troubleshoot your query for you. If what I worked out for you s not working, then your content model does not match the data structure that you shared.
Ok, I can do that. Mind if we DM please?
Please don't DM me. I'm unable to provide support in a private channel. Since we're a community it's important that answers are discoverable for others that may have the same question. If you would like private dedicated support, you can upgrade to an Enterprise plan .
Ah, apologies. Noted about the private channel.
We've double and triple-checked multiple times the posted content model, but I'll check again.

As far as Enterprise, we'll have to see. This particular project is a small non-profit already on the non-profit plan, so Enterprise plan will likely be out of scope.
If your dataset is public, you can share the url that Vision outputs for the query. If not, I can add myself to your project and see if I can get it to work in Vision.
Ok, that works. Let me see what our setup is.
Ok, checked it out. Our dataset is private. How do I share the URL here safely?
Go it! If it's private, you can either share your project ID and I'll add myself to the project, or I can DM you my email address and you can invite me. Whichever is more comfortable for you.
Sure thing, I can invite you.
Got it! My problem was that in Vision, I was using an old API version. Switching to a newer version made the query work. Ultimately the suggested code worked:
*[_type == 'publisher' && code == 'PUB1']{
  'authors': *[_type == 'author' && ^._id in books[]->.publisher._ref]
}
Thanks much for the assist
user M
!

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?