πŸ‘€ Our most exciting product launch yet πŸš€ Join us May 8th for Sanity Connect

GROQ Readability Helper πŸ€“

By Hrithik Prasad & Jono Alford

Less is more - We're breaking down some of the core helpers we use when building our websites

This can help you extend your groq pretty easy 😌


export const refExtend = (
  name: string,
  isArray = false,
  ext: Array<string> = [],
) => groq`
  defined(${name})=>{
    ${name}${isArray ? '[]->' : '->'}{
      ...,
      ${ext.join(',')}
    }
  }
  `;

export const extent = (
  name: string,
  isArray = false,
  ext: Array<string> = [],
) =>
  groq`defined(${name})=>{
    ${name}${isArray ? '[]' : ''}{
      ...,
      ${ext.join(',')}
    }
  }`;


Creating fragments with above functions are neat πŸ˜‰


export const internal = groq`internal->{${slug}}`;

export const checkBrokenLink = groq`"isBroken":select(
  defined(internal)=>false,
  defined(external)=>false,
  true
),
`;

export const extractLink = groq`"href": select(
  defined(internal)=>internal->slug.current,
  defined(external)=>external,
  null
)`;

export const link = extent('link', false, [internal]);

export const customLink = extent('customLink', false, [
  internal,
  extractLink,
  checkBrokenLink,
]);

export const markDefs = extent('markDefs', true, [customLink]);

export const button = extent('url', false, [
  internal,
  extractLink,
  checkBrokenLink,
]);

export const buttons = extent('buttons', true, [button]);

export const richText = extent('richText', true, [
  markDefs,
  buttons
]);

export const spotLight = refExtend('spotlight', false, []);

export const faqs = refExtend('faqs', true);

export const category = refExtend('categories', true);

export const pageBuilder = extent('pageBuilder', true, [
  richText,
  buttons,
  category,
  faqs,
  videoEmbed,
  link,
]);

export const author = refExtend('author');

This is the end goal making the query more readable and clean 😏


// author , category, richText, 
// pageBuilder, link 
// are fragments for the articles 
export const articleQuery = groq`*[_type == "article" 
   && defined(slug.current) 
   && slug.current == $slug][0]{
    ...,
    ${[
      author, 
      category, 
      richText,
      pageBuilder,
      link
      ].join(',')}
  }`;

Before and After query πŸ‘€

// Before Cleaning

const pageQuery = groq`*[_type == "page" 
  && slug.current == $slug][0]{
    ...,
    pageBuilder[]{
      ...,
      buttons[]{
        ...,
        url{
        ...,
        internal->{
          slug 
        } 
      } 
    }, 
    categories->{ title },
    richText[]{
      ...,
      markDefs[]{
        ...,
        customLink{ 
          ...,
          internal->{
            slug 
            
          }
        } 
      } 
    }, 
    link{
      ...,
      internal->{ 
        slug
        } 
    } 
  } 
}`;

// After Cleaning 

export const articleQuery = groq`*[_type == "article"
 && defined(slug.current) 
 && slug.current == $slug][0]{
  ...,
  ${[author, category, richText, pageBuilder, link].join(',')}
}`;

One issue that is often discussed with GROQ is that its syntax can become unwieldy and difficult to manage as queries become more complex, especially when using long and repetitive fragments. This can reduce the code's readability and maintainability, making it difficult for developers to modify and update their queries efficiently. This issue emphasizes the importance of using best practices and effective coding techniques when using GROQ to keep queries manageable and easy to understand even as they become more complex.

Any more questions?

We're always trying to improve knowledge around Sanity, GROQ & Next.js. We've tried to collate a bunch of questions we wanted answers to when we first started working with the composable content cloud. If you have any more questions you'd like answers to, ☎️ Get a meeting booked in or drop us an email at

Contributors

Other schemas by authors

Portable Text Mock Content

If you're looking to mockup portable text in Storybook without a Sanity backend, this is the schema you're looking for

Go to Portable Text Mock Content

One or the other validation

This validation can be used if you have two fields and you require one or the other to be filled

Roboto Studio
Go to One or the other validation