Optimizing a query function to fetch filtered videos

1 replies
Last updated: Jun 22, 2023
export async function getFilteredVideos( limit,
filterGrade,
filterCategory,
search,
sort,
type = "Lesson Video",
subCategory
) {
console.time("videos fetch");
let query = `*[_type == "video"]{${videoFields}}`;

query += `[type.name == "${type}"]`;

if (filterGrade && filterGrade !== "All Grades") {
query += `[ "${filterGrade}" in grade[].label ]`;
}

if (filterCategory && filterCategory !== "All Categories") {
query += `[ "${filterCategory}" in category[].title ]`;
}

if (subCategory && subCategory !== "All Subtopic") {
query += `[subCategory.title match "${subCategory}"]`;
}

if (search && search !== "All") {
query += `[name match "${search}*"]`;
}

if (sort && sort === "longest") {
query += `| order(duration desc)`;
}

if (sort && sort === "shortest") {
query += `| order(duration asc)`;
}

if (sort && sort === "relevance") {
query += `| order(type.name desc)`;
}

query += `${limit}`;

const results = await client.fetch(query);
console.timeEnd("videos fetch");
return results;
}
anyone who can help my make this query faster
AI Update

Looking at your query, there are several performance issues that are likely causing slowness. Here's how to make it significantly faster:

Main Issues

1. String concatenation is building an invalid GROQ query

Your current approach concatenates filter conditions incorrectly. Each filter adds another array slice [condition], which doesn't create valid GROQ syntax. You need proper boolean logic with && operators.

2. No indexes are being utilized

The query starts with *[_type == "video"] which is good, but subsequent filters aren't optimized for the query engine.

3. Multiple reference dereferencing

Fields like grade[].label and category[].title suggest you're dereferencing arrays of references, which is expensive.

Optimized Solution

export async function getFilteredVideos(
  limit,
  filterGrade,
  filterCategory,
  search,
  sort,
  type = "Lesson Video",
  subCategory
) {
  console.time("videos fetch");
  
  // Build filter conditions as an array
  const conditions = ['_type == "video"', `type.name == $type`];
  
  if (filterGrade && filterGrade !== "All Grades") {
    conditions.push(`$filterGrade in grade[].label`);
  }
  
  if (filterCategory && filterCategory !== "All Categories") {
    conditions.push(`$filterCategory in category[].title`);
  }
  
  if (subCategory && subCategory !== "All Subtopic") {
    conditions.push(`subCategory.title match $subCategory`);
  }
  
  if (search && search !== "All") {
    conditions.push(`name match $search`);
  }
  
  // Combine all conditions with &&
  const filterClause = conditions.join(' && ');
  
  // Build order clause
  let orderClause = '';
  if (sort === "longest") orderClause = '| order(duration desc)';
  else if (sort === "shortest") orderClause = '| order(duration asc)';
  else if (sort === "relevance") orderClause = '| order(type.name desc)';
  
  // Build final query with parameters
  const query = `*[${filterClause}] ${orderClause} [0...${limit}] {${videoFields}}`;
  
  const results = await client.fetch(query, {
    type,
    filterGrade,
    filterCategory,
    subCategory,
    search: search ? `${search}*` : undefined
  });
  
  console.timeEnd("videos fetch");
  return results;
}

Key Improvements

1. Use query parameters: Passing values as parameters (the second argument to client.fetch()) is more secure and allows the query engine to optimize better.

2. Proper filter syntax: Combining conditions with && creates a valid GROQ filter that the query engine can process efficiently.

3. Move projection to the end: According to GROQ query optimization best practices, you should filter and sort first, then project fields. This reduces the amount of data processed.

4. Optimize array slicing: Use [0...${limit}] instead of appending the limit - this is the correct GROQ syntax for slicing.

Additional Optimization Tips

If this is still slow with large datasets:

  • Add indexes to frequently filtered fields like type.name and grade[].label (if you're on a Growth plan or higher)
  • Reduce reference dereferencing: If grade[].label and category[].title are references being dereferenced, consider denormalizing this data or using a more efficient data structure
  • Limit your projection: Only include fields in videoFields that you actually need
  • Consider pagination: If you're showing paginated results, implement cursor-based pagination which is more efficient than offset-based pagination for large datasets

The query parameter approach combined with proper filter syntax should give you a significant performance boost immediately.

Do not post your question multiple times.

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?