페이지네이션과 필터링을 구현할 때, 필터링된 상품의 개수가 총 몇 개인지에 대해 COUNT
하여 개수를 알아낸 뒤, 이를 클라이언트에 보내고, 이후에 페이지네이션과 필터링을 하였다. 아래와 같이 말이다.
const totalCount = async (categoryString) => {
try {
return await appDataSource.query(
`SELECT
count(id) AS cnt
FROM
products
${categoryString}
`
);
} catch (err) {
console.log(err);
const error = new Error("Fail to count!");
error.statusCode = 500;
}
};
하지만 호준님께서 이것 말고도 다른 방법이 있을 것이라며 조언해주셨고, 이에 대해 여러 구글링을 해보다가 알게 된 것이 있다. 바로 SQL_CALC_FOUND_ROWS
/ FOUND_ROWS
이다.
SQL_CALC_FOUND_ROWS
/ FOUND_ROWS
FOUND_ROWS
는 LIMIT을 제외하고 count를 저장할 수 있는 역할을 하는데, 즉, LIMIT과 상관없이 조건에 해당하는 Row를 전체 스캔한다. 특히 페이지네이션을 사용할 때 필터링이 같이 적용된다. 따라서 백엔드에서 API의 total count 정보를 전달해줄 때 유용하다.
나는 이를 이렇게 활용하였다.
const productsList = await queryRunner.query(
`SELECT SQL_CALC_FOUND_ROWS
p.id AS productId,
p.korean_name AS koreanName,
p.english_name AS englishName,
p.price,
p.thumbnail
FROM products p
${whereClause}
ORDER BY ${sortMethod[sort]}
LIMIT ${limit} OFFSET ${offset}`
);
const [totalCount] = await queryRunner.query(
`SELECT FOUND_ROWS() AS totalCount`
);
return { productsList, totalCount };
productsList
에 페이지네이션과 필터링한 상품의 목록을, 그리고 totalCount
에 필터링된 상품들의 개수를 알 수 있도록 코드를 작성하였다. FOUND_ROWS()
를 사용하므로써 개수를 알기 위해 열 줄이 넘게 작성되었던 코드가 단 세 줄만에 작성될 수 있었다.