Building a GROQ query programmatically for a hierarchical route schema.

10 replies
Last updated: Jun 9, 2022
hi, can this query be written in a more generic way?query:

*[
  slug.current == $slug[2] &&
  parentPage->slug.current == $slug[1] &&
  parentPage->parentPage->slug.current == $slug[0]
 ]
params:

{
  "slug": ["/","parent", "page"]
}

Jun 9, 2022, 4:10 PM
I just did a fun experiment where I iterated through the param with

$slug[] { "slug" : ^ }
and nothing else, and it looped through the values at least, but I can't think of a way to not only fetch the index automatically but add cascading amounts of parents
with dereferencing.
I think the closest you could get is writing it programmatically on a loop, concatenating them to
form the query when developing and letting it run that. I'm no expert, though.
What constitutes a parent page in this case? Is there an actual hierarchy? Or is it designated?
Jun 9, 2022, 4:51 PM
i have route schema and in there, you can define another route as the parent page, to create a hierarchy of pages…

export default {
  name: "route",
  type: "document",
  title: "Route",
  icon: LinkIcon,
  fields: [
    {
      name: "parentPage",
      type: "reference",
      to: {
        type: "route",
      },
    },
    {
      name: "slug",
      type: "slug",
      title: "Slug",
    },
  ]
}

Jun 9, 2022, 4:57 PM
Hmm. I know there are operands(?) like ^ for parent and @ for "this" but I don't think there's support for recursion or forcing dereferencing down to a certain depth. Making a schema for routes is clever, though.
Jun 9, 2022, 4:59 PM
ok… so it looks like an feasible option is to iterate over the array and create and concatenate the query before sending it
Jun 9, 2022, 5:00 PM
Awesome. Yeah ideally you'd be able to tee yourself automagically with just the one move but it's basically infinite power to combine them and make the formation of the query intelligent.
Jun 9, 2022, 5:03 PM
Hi, in this particular case the best solution is probably to build the GROQ query programmatically from string fragments.
Jun 9, 2022, 8:10 PM
ok, this is my solution now… a little bit of a FrankenGroq but it works 🙂
const slug = [null, 'parent', 'page']
const parentPageSelector = `parentPage->`;
const idQuery = slug
    .map(
        (_segment, index, slug) =>
            `${parentPageSelector.repeat(index)}slug.current == $slug[${slug.length - 1 - index}]`
    )
    .join('&& \n');

const query = `*[${idQuery}]`;
Jun 9, 2022, 9:13 PM
Oh man, breaking out the repeat() ...good times 😃
Jun 9, 2022, 10:32 PM
haha… yes… i have not used
string.repeat()
in ages
Jun 9, 2022, 10:35 PM
That's one of those ones where you're in a corner and you're like, "Wait, there's gotta be something that does that" and that's the first day you use it and, ideally, the only time...but it finds a way back!
Jun 9, 2022, 10:38 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?