NestJS中Reflect.getMetadata TypeError错误排查及单集合存储方案求助
我有两个NestJS模块:User和Admin。两者Schema一致,仅默认角色不同(User默认角色为0,Admin默认角色为1)。因Admin属于用户范畴,希望使用MongoDB单个users集合存储两者的注册数据,但操作中出现如下TypeError错误:
[Nest] 756 - 15/12/2022, 3:54:34 pm ERROR [ExceptionHandler]
TypeError:
at Reflect.getMetadata (D:\Noum\Data\CYBRNODE\MAN STACK\Cybrnode-Blog-Backend\Cybr-Blog-Nest-Backend\node_modules\reflect-metadata\Reflect.js:354:23)
at DependenciesScanner.isInjectable (D:\Noum\Data\CYBRNODE\MAN STACK\Cybrnode-Blog-Backend\Cybr-Blog-Nest-Backend\node_modules@nestjs\core\scanner.js:302:26)
现有代码
user.module.ts
@Module({ imports: [ forwardRef(() => { AdminModule; }), MongooseModule.forFeature([ { name: User.name, schema: userSchema, }, ]), ], controllers: [UserController], providers: [UserService, AdminService], exports: [UserService], }) export class UserModule {}
admin.module.ts
@Module({ imports: [ forwardRef(() => { UserModule; }), ], controllers: [AdminController], providers: [AdminService, UserService], exports: [AdminService], }) export class AdminModule {}
admin.service.ts(注入UserModel以操作users集合)
@Injectable() export class AdminService { constructor( @InjectModel(User.name) private readonly adminModel: Model<userDocument>, ) {} }
错误原因与修复步骤
1. 修复forwardRef返回值
你的forwardRef回调只写了模块名但没有return,导致Nest无法正确解析循环依赖,这是触发Reflect.getMetadata错误的核心原因。
2. 清理重复注入的服务
两个模块互相注入对方服务会导致依赖实例混乱,应该通过模块导出+导入的方式共享服务,而非重复添加到providers。
3. 确保AdminModule能获取UserModel
AdminService需要注入UserModel,需确保该模型在当前模块或导入的模块中可用,这里通过UserModule导出MongooseModule实现。
修复后的代码
user.module.ts
@Module({ imports: [ forwardRef(() => AdminModule), // 修复:直接返回AdminModule MongooseModule.forFeature([ { name: User.name, schema: userSchema, }, ]), ], controllers: [UserController], providers: [UserService], // 移除AdminService,避免重复注入 exports: [UserService, MongooseModule], // 导出MongooseModule,让AdminModule能访问UserModel }) export class UserModule {}
admin.module.ts
@Module({ imports: [ forwardRef(() => UserModule), // 修复:直接返回UserModule ], controllers: [AdminController], providers: [AdminService], // 移除UserService,通过导入UserModule使用 exports: [AdminService], }) export class AdminModule {}
admin.service.ts(无需修改,确保User相关类型正确导入即可)
@Injectable() export class AdminService { constructor( @InjectModel(User.name) private readonly adminModel: Model<userDocument>, ) {} }
额外优化建议
其实这个场景没必要拆分两个模块和服务,因为只是默认角色不同,完全可以在UserService里新增创建管理员的方法,复用同一个模型:
@Injectable() export class UserService { constructor(@InjectModel(User.name) private readonly userModel: Model<userDocument>) {} // 创建普通用户 async createUser(dto: CreateUserDto) { return this.userModel.create({ ...dto, role: 0 }); } // 创建管理员 async createAdmin(dto: CreateAdminDto) { return this.userModel.create({ ...dto, role: 1 }); } }
这样完全避免了循环依赖问题,代码更简洁,也符合单一集合的设计初衷。
内容的提问来源于stack exchange,提问作者M Nouman

