🔮 Sanity Create is here. Writing is reinvented. Try now, no developer setup

Understanding the use of `^` and `@` operators in GROQ queries for accessing parent and current scopes.

6 replies
Last updated: May 29, 2023
What should my GROQ be to get the root document's title from a custom object's field? I feel like I should be able to just use
[@].title
but that's just returning null.
May 29, 2023, 5:15 PM
You can traverse up in scope using the parent operator (
^
), and they can be chained together (e.g.,
^.^.title
).
May 29, 2023, 7:44 PM
What's the "special variable"
@
for then? I thought that I could access the root document with it?
May 29, 2023, 8:20 PM
@
is whatever’s currently in scope.
May 29, 2023, 8:21 PM
Maybe this will help because I'm still confused. The following code is from a custom seo object which I've added to my page document schema. I want to get the title from the page document this object is being used on.
// studio/schemas/objects/seo.ts

initialValue: async (_, context) => {
    const client = context.getClient;
    const title = await client({ apiVersion })?.fetch(`[@][].title`);

    return title || '';
},
May 29, 2023, 8:26 PM
Sorry, I should clarify.
@
is whatever’s in scope of the current GROQ query, but it can’t be used to establish a query. In this case, the query being provided to
client.fetch
doesn’t provide any context about what it’s after, as the client will not infer the current document and pass it along. Instead, it will usually be provided with an
_id
, which will be used in the query.
Here’s an example that hopefully shows how
^
and
@
work. When you dereference, you are performing a subquery not unlike the implementation of
author
below (so the
author
filter is close to or the same as `author->`—minus the projection with `authorDetails`—but I’ve used this method to demonstrate a point.

*[_type == 'post'][0]{
  'author': *[_type == 'author' && _id == ^.author._ref]{
    'authorDetails': @
  },
  'postDetails': @
}
In the query
*[_type == 'author' && _id == ^.author._ref]
, we want to compare the
_id
that’s in scope (i.e., of the author) to the
author._ref
value of the parent (i.e., the post). The
^
operator lets us do this by looking at the parent scope. This only works because we have a
post
document in the context of this GROQ query. We couldn’t query for
*[_type == 'author']
and be able to use the
^
operator to look any higher than the root.
The
@
in
authorDetails
is returning us the current scope at that point, which is in the context of the
*[_type == 'author' && _id == ^.author._ref]
query.
The
@
in
postDetails
is returning us the current scope at that point, which is in the context of the
*[_type == 'post'][0]
query.
As for your desire to fetch a field on the current document in the
initialValue
callback, I don’t believe that will be possible since at that point, the document doesn’t exist yet. Initial values are only set on document creation, so there won’t be a title to fetch. Hope this helps!
May 29, 2023, 10:10 PM
Hey thanks for that detailed response! That makes much more sense now.
May 29, 2023, 11:45 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?