GROQ conditional reference dereferencing not working in API 2021-03-25+

4 replies
Last updated: Apr 15, 2021
Hi everyone! I seem to be having trouble with the new GROQ api. I've got an old query that doesn't seem to be working at all in the new version and I cant seem to figure out how to fix it. Essentially I have an array of a mix of references and objects. Previously I was able to run the following query to follow the reference for specific types and get containing information. Is there any equivalent for this in the new api (2021-03-25+).

menuItems[]{
  _type == "menuPage" => ^->{
    ...,
  },
}
Schema is here as well to show the structure!


fields: [
    {
      name: "menuItems",
      title: "Menu Items",
      type: "array",
      of: [
        {
          title: "Menu Page",
          name: "menuPage",
          icon: MenuPageIcon,
          type: "reference",
          to: [{ type: "menuPage" }],
        },
        {
          title: "Internal Link",
          icon: InternalLinkIcon,
          type: "internalLink",
        },
        {
          title: "External Link",
          icon: ExternalLinkIcon,
          type: "externalLink",
        },
      ],
      validation: (Rule) => Rule.unique(),
    },
  ],
AI Update

I see what's happening here! The syntax you're using with ^-> isn't actually a documented GROQ operator - it looks like you might have been combining ^ (parent scope) with -> (dereference) in a way that may have worked in an older parser or was part of custom code.

For your use case with a mixed array of references and objects, here's the correct approach in GROQ API version 2021-03-25 and later:

menuItems[]{
  _type == "menuPage" => @->,
  _type != "menuPage" => @
}

What this does:

  • @ represents the current item in the array iteration
  • @-> dereferences the current item if it's a reference
  • The conditional _type == "menuPage" => @-> only dereferences when the type is menuPage
  • Other types (internalLink, externalLink) pass through unchanged with @

You can also be more explicit about each type:

menuItems[]{
  _type == "menuPage" => @->,
  _type == "internalLink" => @,
  _type == "externalLink" => @
}

Alternative approach using coalesce:

As mentioned in the GROQ joins specification, you can use coalesce to elegantly handle mixed content:

menuItems[]{
  ...,
  "resolved": coalesce(@->, @)
}

This attempts to dereference first (@->), and if the item isn't a reference, it returns the object as-is (@). However, the conditional approach gives you more explicit control over which types get dereferenced.

Why this works: The -> operator in GROQ internally executes a subquery to resolve references. When you use @-> in an array projection, you're telling GROQ to dereference the current item in the iteration. For non-reference items (your inline internalLink and externalLink objects), the dereference simply doesn't apply, so using the conditional ensures you only dereference what needs dereferencing.

The key is using @-> (not ^->) to dereference items within array projections!

Show original thread
4 replies
The reason it worked before, I believe, was due to a bug with the parent hat operator
^
 which wouldn't always select the upper scope. I believe you can get it to work if you change your query to using the "this" operator:
@


menuItems[]{
  _type == "menuPage" => @->{
    ...,
  },
}
Read more here:
https://www.sanity.io/changelog?platforms=GROQ#618800c971b3
🙌 That worked perfectly thanks
user Y
! I was just reading through the patch notes and noticed that bug fix but had no idea the
@
operator existed!
🙌 That worked perfectly thanks
user Y
! I was just reading through the patch notes and noticed that bug fix but had no idea the
@
operator existed!
The reason it worked before, I believe, was due to a bug with the parent hat operator
^
 which wouldn't always select the upper scope. I believe you can get it to work if you change your query to using the "this" operator:
@


menuItems[]{
  _type == "menuPage" => @->{
    ...,
  },
}
Read more here:
https://www.sanity.io/changelog?platforms=GROQ#618800c971b3

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?