Using a given parameter as a where condition in GROQ in Sanity.io

2 replies
Last updated: Dec 12, 2023
Hey, any way to set a given param as a where condition in GROQ?
Like if I generate a very complex condition outside the query, because I need multiple other resources to get the wanted paramters and values from another api endpoint, simplified, something like this :


 const queryParams = {
    //...
    superComplexCondition: `(.... && .... && (... || ...))`,
  }

  const products = await sanityFetch<ProductsQueryResponseType>({
    query: productsQuery,
    params: {
      ...queryParams,
      language: 'en',
    },
    cache: 'no-store',
  })

groq`
*[_type == "product" && $superComplexCondition]{
  _id,
  title
}
Maybe, there's a trick?
🙂
Thank you!
AI Update

Unfortunately, you cannot inject query fragments, conditions, or operators as string parameters in GROQ. As explained in the GROQ Parameters documentation, parameters using the $ syntax are designed to inject values only - they must be JSON literals and cannot contain GROQ expressions, field paths, or operators.

This is by design for security and parsing reasons. Your approach won't work:

// ❌ This won't work
*[_type == "product" && $superComplexCondition]

Your Best Options

1. Build the entire query string dynamically (most flexible)

Instead of using parameters for the condition, construct the full GROQ query as a string:

const superComplexCondition = `(status == "active" && price > 100 && (category == "electronics" || category == "gadgets"))`;

const productsQuery = `*[_type == "product" && ${superComplexCondition}]{
  _id,
  title
}`;

const products = await sanityFetch<ProductsQueryResponseType>({
  query: productsQuery,
  params: {
    language: 'en',
  },
  cache: 'no-store',
});

Security note: If you're building queries from any user input, be extremely careful about GROQ injection attacks. Sanitize and validate all values.

2. Use multiple parameters for individual values (safer)

Break down your complex condition into individual value parameters that GROQ can handle:

const queryParams = {
  status: 'active',
  minPrice: 100,
  category1: 'electronics',
  category2: 'gadgets',
};

const productsQuery = groq`
  *[_type == "product" && 
    status == $status && 
    price > $minPrice && 
    (category == $category1 || category == $category2)
  ]{
    _id,
    title
  }
`;

const products = await sanityFetch({
  query: productsQuery,
  params: queryParams,
});

This approach keeps you safe from injection issues while maintaining flexibility. As noted in this discussion about GROQ security, using parameters for values prevents syntax errors from special characters and GROQ injection attacks.

3. Server-side query builder function

If your conditions are truly complex and dynamic based on external API data, consider building a validated query builder:

function buildProductQuery(externalData: ComplexConditions) {
  // Transform your external API data into safe GROQ conditions
  const whereClause = constructSafeWhereClause(externalData);
  
  return `*[_type == "product" && ${whereClause}]{
    _id,
    title
  }`;
}

The first approach (dynamic query string building) is the most common solution when you need truly dynamic conditions based on complex external data from another API endpoint, but remember to handle any untrusted input carefully to avoid injection vulnerabilities.

The only way would be to use template literals:

groq`
*[_type == "product" && ${superComplexCondition}]{
  _id,
  title
}
Ok thank you

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?