如何在Prisma中单次请求完成findMany与count查询并保留类型?
解决方案
1. 解决重复条件+类型丢失问题(推荐方案)
直接复用Prisma自动生成的CategoryWhereInput类型定义筛选条件,既能避免重复编写where逻辑,又能保留完整的TypeScript类型提示,同时通过Promise.all并行执行查询,减少总耗时:
async findAll( { onlyParents }: ParamsCategoryDto, user: ITokenPayload | undefined, ): Promise<IFilterRes> { // 用Prisma生成的类型定义筛选条件,自动保留类型提示 const where: Prisma.CategoryWhereInput = { user_id: user?.id, // 按需添加其他筛选逻辑,比如onlyParents的判断 ...(onlyParents ? { parent_id: null } : {}), }; // 并行执行查询,复用数据库连接池,效率比串行更高 const [categories, total] = await Promise.all([ this.prisma.category.findMany({ where }), this.prisma.category.count({ where }), ]); return { pagination: { total }, data: categories, }; }
2. 单数据库查询实现(极致性能场景)
如果需要严格意义上的一次数据库请求完成数据和总数查询,可以用Prisma的原生SQL查询能力,但需要手动处理类型映射,适合对性能有极致要求的场景:
async findAll( { onlyParents }: ParamsCategoryDto, user: ITokenPayload | undefined, ): Promise<IFilterRes> { const userId = user?.id; // 动态拼接筛选条件,注意用Prisma的raw方法避免SQL注入 const extraCondition = onlyParents ? prisma.raw('AND parent_id IS NULL') : prisma.raw(''); // 原生SQL同时查询总数和数据 const queryResult = await this.prisma.$queryRaw` SELECT (SELECT COUNT(*) FROM category WHERE user_id = ${userId} ${extraCondition}) AS total, json_agg(row_to_json(c)) AS data FROM category c WHERE c.user_id = ${userId} ${extraCondition} `; // 手动断言类型,匹配你的返回结构 const { total, data } = queryResult[0] as { total: number; data: Category[] }; return { pagination: { total }, data, }; }
说明
- 推荐第一种方案:代码简洁、类型安全、并行查询的性能损耗可以忽略,是Prisma实现分页的常规做法
- 第二种方案仅在需要极致性能时考虑,需要注意SQL注入风险(Prisma的参数化查询会帮你处理大部分风险,但动态拼接条件时要谨慎)
内容的提问来源于stack exchange,提问作者SPR1NG
相关产品推荐
相关产品推荐

