sanitygroq

Can I reach a grandparent from a GROQ query?


I'm trying to run a GROQ query for my Sanity.io project that should filter out child documents that contain references based on a grandparents id. Is it possible to do so?

I've come to an understanding that for similar scenarios I could use the parent operator like so:

references(^._id)

But in my case, I need the grandparent id, so I cannot make any use of the parent operator the way I've wrote the query now.

I can also clearly read in the documentation:

Known issue The ^ operator currently only works from subqueries. In all other scopes, it returns the root of the current scope, not the parent scope. It is also not possible to use ^ to refer to grandparent scopes.

But no information about a workaround.

The query currently looks like this. I need pages only that refer to the team id. But right now, using the references(^._id) in the current position (pages), I'm only getting a reference id from the parent (sports) and not from the grandparent (teams) which I need.

*[_type == 'client' && alias == 'ipsum']{
    _id, name, teams[]->{
        _id, name,
        sports[]->{
            name,
            "pages": *[_type=='page' && references(^.id)]
        }
    }
}

Thanks in advance, any help at all will be greatly appreciated.


Solution

  • Very short answer: You're correct in that there's currently no way of referencing a grandparent in GROQ.

    However, there's usually a way to get around such obstacles.

    If your schema does not contain a direct relationship between Sport and Page, you might be better off aggregating pages by team:

    *[_type == 'client' && alias == 'ipsum']{
      _id, name, teams[]->{
        _id, name,
        sports[]-> {_id, name},
        "pages": *[_type=='page' && references(^._id)]
      }
    }
    

    This would reduce the amount of data transferred for each query, because you're no longer lifting an identical set of pages for each sport.

    If your schema does conatain a direct relationship between Sport and Page, e.g. someSport.page._ref, then the following query would include only those pages:

    *[_type == 'client' && alias == 'ipsum']{
      _id, name, teams[]->{
        _id, name,
        sports[]-> {
          _id,
          name,
          "pageId": page._ref
        },
        "sportPages": *[_type=='page' && references(^._id) && _id in ^.sports[].page._ref]
      }
    }
    

    In the latter case, you might prefer to do some client side data wrangling to get the various sportPages nested correctly under each sport.

    Disclaimer: I haven't tried this out on actual data, but I'm hoping the above queries might be the inspiration you need to get it working?