Nest.js/Mongoose:为啥我的预保存钩子无法触发?

Posted

技术标签:

【中文标题】Nest.js/Mongoose:为啥我的预保存钩子无法触发?【英文标题】:Nest.js/Mongoose: Why is my pre save hook failing to be triggered?Nest.js/Mongoose:为什么我的预保存钩子无法触发? 【发布时间】:2020-10-14 15:32:48 【问题描述】:

我刚开始使用 Nest.js,到目前为止一切顺利。但是,我遇到了一个问题,即我的用户模式中的猫鼬预保存钩子没有被触发。这应该很简单,但无论出于何种原因,密码都以纯格式而不是散列形式保存。什么给了?

还有一个小问题 - 在使用 @Prop 装饰器时,如何定义引用另一个模式的字段? profile 字段应该是 mongoose.schema.types.objectid 在没有装饰器的情况下,它只是 profile: type: mongoose.Schema.Types.ObjectId, ref: 'Profile' 。

以下是相关的sn-ps。

用户架构

import  Prop, Schema, SchemaFactory  from '@nestjs/mongoose';
import  Document  from 'mongoose';

@Schema(
  timestamps: true,
)
export class User extends Document 
  @Prop( required: true )
  fullname: string;

  @Prop( required: true, unique: true )
  username: string;

  @Prop( required: true, unique: true, lowercase: true )
  email: string;

  @Prop( required: true )
  password: string;

  @Prop( required: true, ref: 'Profile' )
  profile: string

  @Prop( required: true, enum: ['admin', 'basic' ])
  role: string


export const UserSchema = SchemaFactory.createForClass(User);

用户模块

import  Module  from '@nestjs/common';
import  MongooseModule  from '@nestjs/mongoose';
import * as bcrypt from 'bcrypt';

import  User, UserSchema  from './user.model';
import  UsersController  from './users.controller';
import  UsersService  from './users.service';

@Module(
  imports: [
    MongooseModule.forFeatureAsync([
      
        name: User.name,
        useFactory: () => 
          const schema = UserSchema;

          schema.pre<User>('save', async function (next: Function) 
            const user = this;

            const salt = await bcrypt.genSalt(10);
            const hashedPassword = await bcrypt.hash(user.password, salt);

            user.password = hashedPassword;

            next();
          );

          schema.methods.comparePasswords = async function (submittedPassword) 
            const user = this;

            await bcrypt.compare(submittedPassword, user.password);
          ;

          return schema;
        ,
      ,
    ]),
  ],
  controllers: [UsersController],
  providers: [UsersService],
)
export class UsersModule 

用户服务

import  Injectable, HttpException, HttpStatus  from '@nestjs/common';
import  InjectModel  from '@nestjs/mongoose';
import  Model  from 'mongoose';
import  JwtService  from '@nestjs/jwt';

import  UsersService  from '../users/users.service';
import  ProfilesService  from '../profiles/profiles.service';
import  User  from '../users/user.model';

@Injectable()
export class AuthService 
  constructor(
    @InjectModel(User.name) private readonly userModel: Model<User>,
    private usersService: UsersService,
    private profilesService: ProfilesService,
    private jwtService: JwtService
  ) 

  async signup(signupData): Promise<any> 
    const foundUser = await this.userModel.findOne( email: signupData.email );

    if (foundUser) 
      throw new HttpException(
        'Email is already in use',
        HttpStatus.BAD_REQUEST
      );
    

    const createdProfile = await this.profilesService.createProfile();

    const createdUser = await this.userModel.create(
      ...signupData,
      profile: createdProfile._id,
      role: 'basic',
    );

    const createdUserCopy =  ...createdUser.toObject() ;

    delete createdUserCopy.password;
    delete createdUserCopy.__v;

    const payload = 
      username: createdUser.username,
      sub: createdUser._id,
    ;

    return 
      user: createdUserCopy,
      token: this.jwtService.sign(payload),
    ;
  

【问题讨论】:

【参考方案1】:

您不能将asyncnext() 结合使用

schema.pre<User>('save', function (next) 
  const user = this;
  console.log(user)
  next();
);

应该工作

【讨论】:

【参考方案2】:

我知道这个问题很久以前就被问过了,但是对于再次面临这个问题的人来说,这里是如何解决它。

useFactory: () => 
          const schema = UserSchema;

          schema.pre<User>('save', async function () 
            const user = this;

            const salt = await bcrypt.genSalt(10);
            const hashPassword = await bcrypt.hash(user.password, salt);

            user.salt = salt;
            user.password = hashPassword;
          );
          return schema;
        

您可以使用返回承诺的函数,而不是手动调用 next()。特别是,您可以使用 async/await。

【讨论】:

以上是关于Nest.js/Mongoose:为啥我的预保存钩子无法触发?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 matlab 中使用带有 libsvm 的预计算内核

为啥新层在修改后的预训练 pytorch 模型中被忽略?

AutoTokenizer.from_pretrained 无法加载本地保存的预训练标记器 (PyTorch)

PyTorch下载的预训练模型的保存位置(Windows)

在后钩中间填充猫鼬中的“查找”

WooCommerce:结帐订单处理钩火问题