Querying a custom type reference in Sanity using groq

9 replies
Last updated: Sep 15, 2022
Hey all! I have a document with a block type, and I've added a reference to a custom type. Like:
{
      name: "body",
      type: "array",
      title: "Body",
      of: [
        { type: "block" },
        { type: "image" },
        {
          title: "Class",
          name: "jccClass",
          type: "reference",
          to: [{ type: "jccClass" }],
        },
      ],
    },
This works fine in the studio, but I'm wondering how to pull that in via groq. I can do this:

*[_type == "post" && slug.current == $slug][0] {
    _id,
    title,
    body,
    "slug": slug.current
  }
Which is fine, but it just pulls reference information into the data, rather than the actual information about jccClass itself. I'm getting this:


{
    "post": {
        "_id": "50bc7aa9-f4af-424d-9184-fbabb2b826ed",
        "body": [
            {
                "_key": "307f83dbbafb",
                "_ref": "df6c5ee6-a80f-4e68-843a-501abaafc6ca",
                "_type": "jccClass"
            },
            ...
        ],
        "slug": "post-one",
        "title": "Post Number One"
    }
}
Can I flesh out the jccClass into an object in the initial query, or will I need to have the component that renders it do the data load itself?

Thanks!
AI Update

You can absolutely dereference (expand) those references directly in your GROQ query! The key is using the -> operator, which tells GROQ to follow the reference and pull in the actual document data.

For your specific case with references inside a body array (portable text), you'll want to use array projection to selectively expand only the reference items. Here's how to modify your query:

*[_type == "post" && slug.current == $slug][0] {
  _id,
  title,
  body[] {
    ...,
    _type == "jccClass" => @->
  },
  "slug": slug.current
}

This syntax works by:

  1. body[] - iterates over each item in the body array
  2. ... - spreads all the existing properties (keeps blocks, images, etc. intact)
  3. _type == "jccClass" => @-> - conditionally dereferences: when the item type is "jccClass", the @ refers to the current item and -> follows the reference

If you want to control which fields from the referenced jccClass document get returned (recommended for performance), you can be more specific:

*[_type == "post" && slug.current == $slug][0] {
  _id,
  title,
  body[] {
    ...,
    _type == "jccClass" => @-> {
      _id,
      title,
      description,
      // whatever fields you need from jccClass
    }
  },
  "slug": slug.current
}

This approach is much more efficient than having your component fetch each reference separately, as it resolves everything in a single query. The Content Lake will handle all the dereferencing server-side.

The -> operator works for any reference type in Sanity, and the conditional projection pattern (_type == "something" => ...) is the standard way to handle mixed arrays like portable text where you have blocks, images, and custom reference types all together.

Hey Brian. You can tweak your query so it resolves the reference. I think it should work like this:
*[_type == "post" && slug.current == $slug][0] {
    _id,
    title,
    body[] {
      ...,
      _type == "jccClass" => {
        @ -> { ... }
      }
    },
    "slug": slug.current
}
Hi! Thanks for this; should I be replacing the "..." with the fields I want, or is this a way to get all of them?
It’s a way to get all of them. 🙂
So you can replace to cherry-pick but you don’t have to.
Thanks! I'm getting a
Attribute or a string key expected
error when I run this. The bit that seems to be tripping Sanity up is
@ -> { ... }
.
Can you try maybe
"foobar": @ -> { ... }
?
That gets rid of the error, but it doesn't load any of the related data:
*[_type == "post" && slug.current == $slug][0] {
    _id,
    title,
    body[] {
      ...,
     type == "jccClass" => {
        "foobar": @ -> { 
         title,
      slug
    
    }
      }
    },
    "slug": slug.current
}
"result":{4 items
"_id":"50bc7aa9-f4af-424d-9184-fbabb2b826ed"
"body":[7 items
0:{3 items
"_key":"307f83dbbafb"
"_ref":"df6c5ee6-a80f-4e68-843a-501abaafc6ca"
"_type":"jccClass"
}
1:{7 items
"_key":"04f4fd05e1ca"
"_type":"block"
"children":[...]2 items
"level":1
"listItem":"number"
"markDefs":[...]1 item
"style":"normal"
}
It should be
_type
, not
type
.
Ahhhhh, thank you!

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?