NestJS集成Mongoose时ClassSerializerInterceptor失效返回空对象
解决NestJS + Mongoose中ClassSerializerInterceptor返回空对象的问题
问题核心:Mongoose查询返回的是Mongoose Document实例,不是你定义的User类实例。ClassSerializerInterceptor依赖class-transformer,默认只识别类实例上的装饰器(比如@Exclude),因此会出现序列化后返回空对象的情况。
以下是几种可行的解决方案:
方案1:转换Mongoose文档为User类实例
先把Mongoose文档转成普通JS对象,再用class-transformer的plainToInstance转换成User类实例,让拦截器能识别装饰器:
首先确保安装依赖:
npm install class-transformer
修改登录接口代码:
import { plainToInstance } from 'class-transformer'; @Post('login') @UseGuards(AuthGuardLocal) @UseInterceptors(ClassSerializerInterceptor) async login(@CurrentUser() user: User) { // 转换文档为普通对象,再转为User类实例 const userInstance = plainToInstance(User, user.toObject()); return { user: userInstance, token: await this.authService.getTokenForUser(user) }; }
方案2:直接在Mongoose Schema中配置排除字段
如果不需要class-transformer的复杂序列化逻辑,可以直接在Schema配置里指定toJSON和toObject的排除字段,让Mongoose在转换为JSON时自动去掉指定属性:
@Schema({ toJSON: { exclude: ['password', 'emailVerifCode'] }, toObject: { exclude: ['password', 'emailVerifCode'] } }) export class User { // ... 原有属性定义 }
这种方式无需使用ClassSerializerInterceptor,更轻量化。
方案3:全局处理Mongoose文档转换
自定义一个拦截器,自动把所有Mongoose文档转成类实例,避免每个接口重复转换:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { plainToInstance } from 'class-transformer'; @Injectable() export class MongooseClassSerializerInterceptor implements NestInterceptor { constructor(private readonly classToTransform: any) {} intercept(context: ExecutionContext, next: CallHandler): Observable<any> { return next.handle().pipe( map(data => { if (data instanceof Object && data.toObject) { return plainToInstance(this.classToTransform, data.toObject()); } // 处理数组类型的返回结果 if (Array.isArray(data)) { return data.map(item => item.toObject ? plainToInstance(this.classToTransform, item.toObject()) : item ); } return data; }), ); } }
使用时在控制器或方法上指定要转换的类:
@Post('login') @UseGuards(AuthGuardLocal) @UseInterceptors(new MongooseClassSerializerInterceptor(User)) async login(@CurrentUser() user: User) { return { user: user, token: await this.authService.getTokenForUser(user) }; }
内容的提问来源于stack exchange,提问作者Simone Provenzano
相关产品推荐
相关产品推荐

