Groq query issue with getting movies and character names for each person in the Sanity movies database.

3 replies
Last updated: Mar 18, 2024
Hi all.Little help with a groq query please. Using the Sanity movies database for a demo purpose. I want to get each
person
get their movies and get their characterName.
This is works except it’s for one person I need to hardcode the
_id
in the
as
bit



*[_type=='person' && _id=="person_sigourney-weaver"]{
  _id,
  "slug": slug.current,
      "image": image{
    asset->{
      url
    }
  },
  name,
  "movies": *[_type=='movie' && references(^._id)]{
    "fakeId": ^._id,
    title,
    "slug": slug.current,
    "poster": poster{
        asset->{
            url
        }
    },
   "as": castMembers[person._ref == "person_sigourney-weaver"]{
     characterName
    }
  }
}
doing this
"as": castMembers[person._ref == ^._id]{
does not work, it returns an empty array.
Where am I going wrong?

And if possible, rather than returning
as
as an array, could it come back a string?
Thank you
AI Update

The issue you're encountering is about scope levels with the parent operator (^). When you're inside the castMembers array filter, you need to reference the person's _id from two levels up, not just one.

Here's what's happening:

  • First ^ = the movie document
  • Second ^ (^.^) = the person document (what you actually need)

So your query should use ^.^._id instead of ^._id:

*[_type=='person']{
  _id,
  "slug": slug.current,
  "image": image{
    asset->{
      url
    }
  },
  name,
  "movies": *[_type=='movie' && references(^._id)]{
    title,
    "slug": slug.current,
    "poster": poster{
      asset->{
        url
      }
    },
    "as": castMembers[person._ref == ^.^._id]{
      characterName
    }
  }
}

The scope breakdown:

  1. You're in the outer person document
  2. You descend into the movie subquery (^._id now refers to the movie)
  3. You descend into the castMembers array filter (you need ^.^._id to get back to the person)

As explained in the GROQ parent operator documentation, you can chain multiple parent operators to traverse multiple levels up in scope.

For returning a string instead of an array, you can use the string::join() function:

"as": string::join(castMembers[person._ref == ^.^._id].characterName, ", ")

This will take all the characterName values and join them into a single comma-separated string. If there's only one character, it'll just return that string. If someone played multiple characters in the same movie, they'll all be listed together.

The complete query would be:

*[_type=='person']{
  _id,
  "slug": slug.current,
  "image": image{
    asset->{
      url
    }
  },
  name,
  "movies": *[_type=='movie' && references(^._id)]{
    title,
    "slug": slug.current,
    "poster": poster{
      asset->{
        url
      }
    },
    "as": string::join(castMembers[person._ref == ^.^._id].characterName, ", ")
  }
}
And of course I fix it seconds after I ask
"as": castMembers[person._ref == ^.^._id]{

double caret - so is that going up outside of
castMembers
and up again to the
references
?
Yes, it’s taking you up to the scope of the
person
projection.
user R
Ain't that how it always goes? 😅

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?