Issue with nested references in GROQ query in Slack thread
The -> operator should work in nested array projections like this—there's no inherent limitation that prevents person->firstname from working when nested. The documentation shows examples like castMembers[].person->name working just fine. So let's troubleshoot the actual cause of your issue.
Most Likely Causes
1. Field Name Mismatch
Double-check that the field is actually named firstname in your person document schema. Try querying just the dereferenced person to see what fields exist:
*[_type == "collection"][0].collection_books[0]->persons[0].person->This will show you the complete person document structure. The field might be named firstName, first_name, name.first, or something else entirely.
2. Draft vs Published Documents (Very Common Gotcha)
According to the Sanity perspectives documentation, when you have unpublished changes, Sanity creates a draft document with an ID prefixed by drafts.. If your referenced person document exists only as a draft, or if you're querying published documents that reference draft versions, the dereference might fail or return incomplete data.
Try specifying the previewDrafts perspective in your query parameters, which prioritizes drafts over published versions:
// In your client configuration
const client = createClient({
// ... other config
perspective: 'previewDrafts',
useCdn: false // Important: CDN doesn't support draft content
})Or test in Vision with the perspective dropdown set to "Preview Drafts".
3. Incorrect Field Path
Looking at your query structure:
"persons": collection_book->persons[]{
"type": type,
"firstname": person->firstname
}Make sure persons is actually an array of objects that each contain a person reference field. The structure should be something like:
{
persons: [
{
type: "author",
person: { _ref: "person-id-123", _type: "reference" }
}
]
}Verify this by checking what person alone returns (without the ->):
*[_type == "collection"][0].collection_books[0]->persons[0].personYou should see {"_ref": "...", "_type": "reference"}. If you see null or undefined, then the field path is wrong.
Debugging Steps
Test incrementally from the inside out:
// Step 1: Can you get the book?
*[_type == "collection"][0].collection_books[0]->
// Step 2: Can you get the persons array?
*[_type == "collection"][0].collection_books[0]->persons
// Step 3: Can you get a specific person reference?
*[_type == "collection"][0].collection_books[0]->persons[0].person
// Step 4: Can you dereference it?
*[_type == "collection"][0].collection_books[0]->persons[0].person->
// Step 5: Can you get the specific field?
*[_type == "collection"][0].collection_books[0]->persons[0].person->firstnameOne of these steps will reveal where the query breaks down.
The Query Should Work As-Is
Your nested dereference pattern is valid GROQ syntax. According to the reference access operator documentation, the -> operator internally executes a subquery to fetch the referenced document, and this works at any nesting level. The issue is almost certainly one of:
- Wrong field name
- Draft/published document mismatch
- Incorrect field path in your schema
- The reference field doesn't actually contain a valid reference
Work through those debugging steps and you should find the culprit!
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.