TypeScript+Prisma电商API带page参数时查询返回空问题排查
问题排查与解决方案
核心问题:Prisma API与Mongoose逻辑不兼容
你参考的JS项目大概率基于Mongoose,它的查询依赖链式Query对象,但Prisma的findMany()直接返回Promise,不支持链式调用find()、limit()、skip()这类方法。你的APIFeatures类完全照搬Mongoose写法,导致所有查询逻辑失效,最终返回空结果。
具体错误点
- 构造函数传入错误对象:你把
prisma.product.findMany()(一个Promise)传给APIFeatures的query参数,而Prisma根本没有可链式调用的查询构建器。后续调用this.query.find()时,Promise没有find方法,直接导致this.query变成无效值。 - 链式调用逻辑不适配Prisma:Prisma的查询是通过给
findMany()传入配置对象(包含where、skip、take等参数)实现的,而非Mongoose那样的链式拼接。
修复方案:重构APIFeatures适配Prisma
重新设计类结构,改为收集查询参数后统一执行Prisma查询:
export class APIFeatures { private model: any; private queryStr: any; private queryOptions: { where: any; skip?: number; take?: number; } = { where: {} }; constructor(model: any, queryStr: any) { this.model = model; this.queryStr = queryStr; } search(): this { if (this.queryStr.keyword) { this.queryOptions.where.name = { contains: this.queryStr.keyword, mode: 'insensitive' // 对应MongoDB的$options: 'i' }; } return this; } filter(): this { const queryCopy = { ...this.queryStr }; const removeFields = ['keyword', 'limit', 'page']; removeFields.forEach(el => delete queryCopy[el]); // 转换gt/gte/lt/lte为Prisma支持的操作符格式 Object.keys(queryCopy).forEach(key => { const value = queryCopy[key]; if (typeof value === 'object') { Object.keys(value).forEach(operator => { if (['gt', 'gte', 'lt', 'lte'].includes(operator)) { queryCopy[key][`$${operator}`] = queryCopy[key][operator]; delete queryCopy[key][operator]; } }); } }); this.queryOptions.where = { ...this.queryOptions.where, ...queryCopy }; return this; } pagination(resPerPage: number): this { const currentPage = Number(this.queryStr.page) || 1; this.queryOptions.skip = resPerPage * (currentPage - 1); this.queryOptions.take = resPerPage; // Prisma中take对应Mongoose的limit return this; } // 统一执行查询 async execute(): Promise<any[]> { return this.model.findMany(this.queryOptions); } }
修改getAllProducts方法:
async getAllProducts(req: Request, res: Response) { try { const resPerPage = 8; const productCount = await prisma.product.count(); const apiFeatures = new APIFeatures(prisma.product, req.query) .search() .filter() .pagination(resPerPage); const response = await apiFeatures.execute(); // 必须await获取查询结果 return res.status(200).send({ success: true, response, productCount }); } catch (error) { res.status(500).send({ message: (error as Error).message }); } }
关键改动说明
- 不再传递
findMany()的Promise结果,直接传入Prisma模型实例。 - 用
queryOptions对象统一收集where条件、分页参数。 - Prisma模糊查询用
contains+mode: 'insensitive'替代MongoDB的$regex语法。 - 新增
execute()方法统一执行查询,必须通过await获取异步结果。
修改后访问localhost:4000/api/products/?page=1即可正常返回第一页产品数据。
内容的提问来源于stack exchange,提问作者Pedro Souza
相关产品推荐
相关产品推荐

