Cut a SyBazar list endpoint by 30% in five queries
The 30% API drop on WaftTech services was not a new cache. Follow these steps on any Mongo or Postgres list that fans out under load — SyBazar and Nepmeds included.
A vendor product list on SyBazar was slow while the handler looked idle. We were waiting on the database. These are the five changes I still run, in order.
Step 1: Log duration per query, not per request
The slowest three queries are usually the whole story. If the handler is fast and the client is slow, you are waiting on I/O.
export async function timed<T>(
name: string,
work: () => Promise<T>,
): Promise<T> {
const started = Date.now();
try {
return await work();
} finally {
console.log(JSON.stringify({ q: name, ms: Date.now() - started }));
}
}
Step 2: Parallelise only independent queries
const [products, vendor] = await Promise.all([
timed("products", () => Product.find({ vendorId }).limit(50).lean()),
timed("vendor", () => Vendor.findById(vendorId).select("name").lean()),
]);
Step 3: Stop hydrating relations you will not serialize
Nepmeds product cards do not need the full inventory history. .lean() and a tight select beat populate-everything.
Step 4: Push filters into the database
- Do not filter large arrays in Node after the query.
- Add an index that matches the filter + sort you actually use.
- Parallelising a bad query still leaves you with a bad query, just sooner.