Are there some limitations on -> when nested like this?

13 replies
Last updated: Oct 23, 2020
OK, so I have a document that contains an array objects, and each object have a reference to another document. GROQ, exemplified with books:

*[_type == "collection"] {

"title": collection_title,

"books": collection_books[]{

"title": collection_book->book_title,

"persons": collection_book->persons[]{

"type": type,

"firstname": person->firstname

}

}

}

Problem here is that
person->firstname
doesn't return anything. If I just write
person
then _ref and _type is returned as expected, but -> doesn't seem to work. Are there some limitations on -> when nested like this?
AI Update

Looking at your query, person->firstname should actually work fine in GROQ - there are no inherent limitations on nested dereferencing. The -> operator works in nested contexts, so the issue is likely something else.

Here's what's probably happening:

Most likely issue: Field naming

Check if the field on the referenced person document is actually called firstname. It might be:

  • firstName (camelCase)
  • first_name (snake_case)
  • name (different field entirely)

When you write person and see {_ref: "...", _type: "reference"}, that confirms the reference exists. But if person->firstname returns nothing, the referenced document probably doesn't have a firstname field.

Solution: Use a projection to see what fields exist

Try this to inspect what's actually in the referenced person document:

*[_type == "collection"] {
  "title": collection_title,
  "books": collection_books[]{
    "title": collection_book->book_title,
    "persons": collection_book->persons[]{
      "type": type,
      "personData": person->
    }
  }
}

This will return the entire referenced person document, showing you what fields are actually available.

Once you know the correct field name:

*[_type == "collection"] {
  "title": collection_title,
  "books": collection_books[]{
    "title": collection_book->book_title,
    "persons": collection_book->persons[]{
      "type": type,
      "firstname": person->firstName  // or whatever the actual field name is
    }
  }
}

Alternative: Use explicit projection syntax

If direct field access still doesn't work (which would be unusual), you can use projection syntax:

"persons": collection_book->persons[]{
  type,
  "firstname": person->{firstname}.firstname
}

Or to get multiple fields from the person:

"persons": collection_book->persons[]{
  type,
  "personInfo": person->{
    firstname,
    lastname,
    email
  }
}

The nested -> operator works fine in GROQ as described in Sanity's projections documentation, so this is almost certainly a field naming issue. Check your actual document structure to confirm the field name.

Try
person->.firstname
and if they’re already named
type
and
firstname
you could try

{
  type,
  person->.firstname
}
Sorry, Theo, but doesn't help. But, thanks! type is returned correctly, as that is a value in the object, but person-> is a reference, and doesn't return anything.
If I use
person->.firstname
instead of
"firstname": person->.firstname
I get an error: "Must be an attribute or a string key".
try
"firstname": @->.firstname
@
denotes the current item in the array
@
denotes the current item in the array
Actually, it depends on your data structure, so an example document would help
try
"firstname": @->.firstname
I solved this particular case by rewriting the structure of the query to a more suitable format. Anyways, I ran into another case of the same:

 "files": collection_set->set_downloads[]{
        "comments": download_comments,
        "type": download_type,
        "url": download_file.asset->url
    },
comments and type works fine, but url returns nothing. I "hacked" it by doing some string replacements on
download_file.asset["_ref"]
instead, but should be fixed the correct way. Tried with @, but no luck. Some relevant schemas attached.
user J
☝️
That looks correct to me. Is it a public dataset? If so you could send me an http url with query and I could tinker with it to see if there's something we're missing
Sure! See PM. Thanks!
This seems to work, you get the extra
set_downloads
level, tho. But at least you get the url
*[_type == 'collection']{
  "files": collection_sets[]{
    ...@.collection_set->{
      set_downloads[]{
        "comments": download_comments,
        "type": download_type,
        "url": download_file.asset->url
      }
    }
  }
}
Thanks, this works!

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?