Using the plus operator to join arrays in GROQ and preserving ordering

6 replies
Last updated: Aug 16, 2021
Is there a way to expand a conditional join within a list of objects?
*[_type == "page" && slug.current == "home"][0]{
  ...,
  contentBlocks[]{
    _type == "reference" =>
    	// I'd like to expand this item so the array of template contentBlocks are additional elements of the parent's array
    	*[_type == 'template' && _id == ^._ref][0]{contentBlocks}
		,
		_type != "reference" => {
      ...,
    }
	}
}
It seems like GROQ might not support data munging like I'd like, and that's ok—I can think of a workaround once the data is on my server—but I am curious.
Aug 16, 2021, 10:11 PM
Current data is returned like this—
[ {block1}, {block2}, {contentBlocks: [{block3}, {block4}]}, ...]
Ideally the query could return

[{block1}, {block2}, {block3}, {block4}, ...]
Aug 16, 2021, 10:13 PM
I've tried a few things with the pipe operator, but haven't figured anything useful out
Aug 16, 2021, 10:13 PM
If you’re on the latest API version, you can use the plus operator to join arrays.
The query may look like this…

*[_type == "page"][0] {
  "all": blocks[_type == "reference"][0]->blocks + blocks[_type != "reference"],
}
Given this data structure:

[
  {
    "_type": "template",
    "_id": "template-1",
    "blocks": [
      {
        "_type": "block",
        "_id": 1,
        "value": 1
      },
      {
        "_type": "block",
        "_id": 2,
        "value": 2
      },
    ]
  },
  {
    "_type": "page",
    "_id": "page-1",
    "blocks": [
      {
        "_type": "reference",
        "_ref": "template-1"
      },
      {
        "_type": "block",
        "_id": 3,
        "value": 3
      },
      {
        "_type": "block",
        "_id": 4,
        "value": 4
      }
    ]
  }
]
Aug 16, 2021, 11:07 PM
Ahh, that's about exactly what I wanted. Awesome you can use the
+
operator like that.
The ordering is important of these blocks though, is there a way to do this while preserving the ordering?

Your example query puts the
reference
type blocks first, then has the rest follow
Aug 16, 2021, 11:25 PM
I guess I could sort them with a
|order(...)
possibly
Aug 16, 2021, 11:25 PM
ohh right,
| order(...)
would work but it would still be tricky if you don’t have something like a value to order with 🤔
If you do use
| order
, wrap the whole thing in a parenthesis:
"all": (blocks[]... + blocks[]...) | order(...)
otherwise only the righthand argument will be sorted!
Aug 16, 2021, 11:35 PM

Sanity– build remarkable experiences at scale

The Sanity Composable Content Cloud is the 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?

Categorized in