使用Drizzle关联查询,能否在应用LIMIT和OFFSET前获取总行数?
在Drizzle关联查询中分页前获取总行数的实现方法
可以实现。核心思路是复用查询过滤条件,分别执行两个查询:一个仅统计符合条件的总行数(无需加载关联数据,提升性能),另一个执行带分页的关联数据查询。
具体实现步骤
- 提取复用的过滤条件函数
把原查询中的动态过滤逻辑抽成独立函数,确保计数查询和分页查询使用完全一致的条件,避免结果不一致:
const getFilmFilter = (film: typeof filmTable.$inferSelect, { eq, and, or, like }) => { const conditions = []; if (params?.textToSearch) { conditions.push(like(film.title, `%${params.textToSearch}%`)); } return or(...conditions); };
- 执行总行数统计查询
使用Drizzle的count函数,基于主表和过滤条件统计总数,不需要加载关联数据:
import { count } from 'drizzle-orm'; // ... const countResult = await this._db.select({ totalCount: count() }) .from(filmTable) .where(getFilmFilter); const totalCount = countResult[0].totalCount;
- 修改原分页查询并组合结果
保留原关联查询逻辑,复用同一个过滤条件,最终返回总数和分页数据的组合结果。
完整修改后的代码示例
import { count } from 'drizzle-orm'; async many(params: FilmQueryParams): Promise<{ totalCount: number; data: FilmDetailed[] }> { // 提取复用的过滤条件 const getFilmFilter = (film: typeof filmTable.$inferSelect, { eq, and, or, like }) => { const conditions = []; if (params?.textToSearch) { conditions.push(like(film.title, `%${params.textToSearch}%`)); } return or(...conditions); }; // 获取符合条件的总行数 const countResult = await this._db.select({ totalCount: count() }) .from(filmTable) .where(getFilmFilter); const totalCount = countResult[0].totalCount; // 执行带分页的关联查询 const filmsDB = (await this._db.query.filmTable.findMany({ limit: params.pageSize, offset: (params.pageNumber - 1) * params.pageSize, with: { categories: { with: { category: true } }, actors: { with: { actor: true } }, language: true, }, where: getFilmFilter, orderBy: (films, { desc }) => [desc(films.releaseYear)], })) as FilmDetailedDB[]; // 返回总数和转换后的数据 return { totalCount, data: this.convertToFilmsDetailed(filmsDB), }; }
关键说明
- 计数查询无需加载关联数据,能大幅降低数据库查询开销,比带着关联关系计数更高效;
- 必须保证过滤条件完全复用,否则会出现总数与分页数据匹配不一致的问题。
内容的提问来源于stack exchange,提问作者user2170991
相关产品推荐
相关产品推荐

