Groq query in Sanity returning null values for some array items

7 replies
Last updated: Jun 30, 2022
in groq v1 the following query:

*[_id == '90ce29b2-cab4-4790-bd97-57e1a97adaf5'][0] {
  'blocks': blocks[]->,
  ...}
returns all the blocks that it can dereference as dereferenced objects, and
everything else as null:


// v1
result: {
  //...
  "blocks": [
  null, // <----------------- missing ref
  {
    "_createdAt": "2022-06-15T17:25:28Z",
    "_id": "f66bfdca-f03a-4bfe-a4fa-cda7537a448a",
    "_rev": "kwp71lZJIGHA037Eneiyj2",
    "_type": "prose",
    "_updatedAt": "2022-06-29T16:37:37Z",
    "content": [ /*...*/]
  }
]
  //...
}
Newer versions don't seem to do anything to the array in question returning
them as references instead.


// v2021-03-25
result: {
  //...
  "blocks": [
    {
      "_key": "293cc22154b1",
      "_ref": "968147d3-a988-4b05-8faa-21a1d3182650",
      "_type": "linkMenuRef",
      "_weak": true
    },
    {
      "_key": "f280c4e697e1",
      "_ref": "f66bfdca-f03a-4bfe-a4fa-cda7537a448a",
      "_type": "proseRef",
      "_weak": true
    }
  ],
  //...
}
Is there still a way to do this with relatively simple syntax?
AI Update

I understand you're experiencing a change in how blocks[]-> behaves between GROQ v1 and newer API versions like v2021-03-25. This is indeed a documented change related to API versioning.

The issue you're seeing is real: in v1, blocks[]-> would dereference references and return null for missing ones, but in v2021-03-25 and later, the dereferencing behavior changed and the syntax returns the reference objects themselves when placed after other projections.

Based on a community discussion around this exact issue, there's a documented workaround:

The solution is to place the spread operator (...) BEFORE your blocks[]-> projection:

*[_id == '90ce29b2-cab4-4790-bd97-57e1a97adaf5'][0] {
  ...,
  'blocks': blocks[]->
}

This ordering matters in v2021-03-25 and later versions. When you put the spread operator first, the dereferencing works as expected, returning dereferenced objects with null for missing references.

This does NOT work:

*[_id == '90ce29b2-cab4-4790-bd97-57e1a97adaf5'][0] {
  'blocks': blocks[]->,
  ...
}

The order of operations in the projection affects how the dereferencing is processed in newer API versions. This appears to be a parsing quirk in how GROQ handles projections when combining dereferencing with the spread operator.

Alternative approach if you want to filter out nulls entirely:

If you want to exclude missing references rather than having null values in your array, you can filter them after dereferencing:

*[_id == '90ce29b2-cab4-4790-bd97-57e1a97adaf5'][0] {
  ...,
  'blocks': array::compact(blocks[]->)
}

Or use a filter to only include defined references:

*[_id == '90ce29b2-cab4-4790-bd97-57e1a97adaf5'][0] {
  ...,
  'blocks': blocks[defined(@->)]->
}

This is a known behavior difference between v1 and v2021-03-25+ related to how the GROQ parser handles projection ordering when dereferencing is involved. The workaround of placing ... first in your projection should restore the v1-like behavior you're looking for.

it's perhaps important to explain that blocks is an array of references, each with a name and each to a specific document type. This allows us to select the kind of thing we want to insert first, then which of those things to insert second, rather than seeing all possible choices in the list at once
This is a cut-down version of the schema:
```
{
"name": "page",
"type": "document",
"title": "Page",
"fields": [
{
"name": "blocks",
"type": "array",
"title": "PageBuilder Sections",
"of": [
{
"type": "reference",
"title": "Link Menu",
"name": "linkMenuRef",
"to": {
"type": "linkMenu"
},
"weak": true
},
{
"type": "reference",
"title": "Rich Text Content",
"name": "proseRef",
"to": {
"type": "prose"
},
"weak": true
}
]
}
]
}
I’ve had issues with having the object expansion ‘…’ AFTER the specific property-projection. Try moving it above maybe!
Also you can extract the types and group them like so:


*[_id == '90ce29b2-cab4-4790-bd97-57e1a97adaf5'][0] {
  ...,
  'linkMenus': blocks[@->_type match 'linkMenu']->{...},
  'prose': blocks[@->_type match 'prose']->{...}
}
Not sure if this helps answer your questipn but thought I’d give it a whirl since it sounded like something I struggled with recently :)
Sorry if the formatting is off, wrote on my phone😅
I know about the grouping you mentioned second, but am trying to avoid that explicit list in this case.
But your suggestion of using the the
...
operator first worked, which is crazy!
Thanks so much for zeroing right in on what seems to be a parsing bug, that unsticks me on a spike that was running over.

Sanity folks, is this a known issue? I couldn't find it
also the issue still happens when using the explicit form `...@`:

*[_id == '90ce29b2-cab4-4790-bd97-57e1a97adaf5'][0] {
  'blocks': blocks[]->,
  ...@
}
The above returns all refs, unexpanded.
Fantastic! Glad I could help! Me and my team were ripping our hair out on this issue exactly 😅

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?