How to resolve references in GROQ queries for page builder components

10 replies
Last updated: May 31, 2022
Hi! I have a question about
GROQ
and
references

I have this query:

*[_type == "page" && pageMetadata.slug == 'test'][0]{
    pageBuilderComponents
}
It returns an array. The problem is that
some (but not all) of these elements are references, while the rest are objects. I would like to resolve the references.
I have tried
pageBuilderComponents[]->
. This will resolve the references correctly, but those elements which were already objects, will now become
null
.
How can I resolve only those elements that are references?
May 27, 2022, 12:31 PM
What does the schema look like? Are the objects inside the pageBuilderComponent or alongside it?
If inside, you may want to list them separately, dereferencing the references along the way but leaving the others untouched.

It may be the case as well that if you call out for the deference-able ones specifically, you can add an ellipsis to catch the rest.
May 27, 2022, 1:09 PM
It is inside yes. The Schema looks like this:

export default {
    name: 'pageBuilderComponents',
    title: 'Page builder Components',
    type: 'array',
    of: [
      { type: 'component1' },
      { type: 'component2' },
      { type: 'component3' },
    ]
  };
When you say list them separately, what do you mean? Do you mean this:
1. First do one GROQ query to get to full array
2. Split it into two lists where one contains only references and contains only objects
3. Do another GROQ query to resolve the references
Or do you mean listing them as two separate arrays in the schema? I would prefer to have it as one array there.
May 27, 2022, 1:20 PM
I meant if there was a page document type as indicated in the original query that, if there were other things besides the page builder array field in the same level as it.
In this case all three of those being references to a different type means that you will need to decide what about those particular referenced types you want to fetch.

If they have their own separate schema or naming conventions you could try an ellipsis to ask for all of it, otherwise first make a condition and then say what to do for each condition.

Have you had a chance to read the documentation on conditions on the GROQ cheat sheet?
May 27, 2022, 2:19 PM
I think you want to use the
coalesce
function:
*[_type == "page" && pageMetadata.slug == 'test'][0]{
    pageBuilderComponents[]{
      'component': coalesce(@->, @)
  }
}
May 27, 2022, 3:50 PM
Oh, that's smart. Coalesce being the one that returns the first non-null value, and the @ sign referencing the root value of the scope (in this case, I believe, whatever the 'each' item is in the 'component' projection, and the -> for dereferencing when applicable. Does that sound about right?
So in plain language, "For each component, if there's something to dereference, grab me that and return the inside bits. If not, try to just grab what's there directly."
May 27, 2022, 3:58 PM
user S
exactly!
May 27, 2022, 4:02 PM
That worked perfectly, thanks! And thanks for the explanation User 🙏
May 27, 2022, 5:55 PM
I realised now that I also need it to recursively resolve references to an unknown depth, as a reference can contain another reference.
From my research, it looks like this is not possible yet in GROQ, is that correct? If so, I guess I would have to set up GraphQL for that instead.
May 30, 2022, 8:36 AM
You can’t currently resolve references to a certain depth, unfortunately. Are there page components inside of your page components?
May 31, 2022, 2:19 PM
Yes
May 31, 2022, 2:21 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?