«исключить» в nestjs работает не так, как ожидалось

#serialization #nestjs

Вопрос:

Я хочу исключить поле пароля из схемы пользователя. Но я никак не могу в этом разобраться.

UserSchema.ts

 export type UserDocument = User amp; Document;

@Schema()
export class User extends BaseSchema {

    @Prop({ type: String })
    firstName: string;

    @Prop({ type: String })
    lastName: string;

    @Prop({ type: String, required: true, unique: true })
    email: string;

    @Prop({ type: String })
    phone: string;

    @Prop({ type: String, required: true, unique: true })
    userName: string;

    @Exclude()
    @Prop({ type: String, required: true })
    password: string;

    @Prop({ type: String })
    avatar: string;

}

export const UserSchema = SchemaFactory.createForClass(User);
 

UserController.ts

 @UseInterceptors(ClassSerializerInterceptor)
    @Get(':id')
    public async getUserById(@Param('id') id: string): Promise<ResponseDto> {
        try {
            const result = await this.userService.getOne({ _id: id });
            return new ResponseDto({
                isSuccess: true,
                message: 'ok',
                data: result
            });

        } catch (error) {
            return new ResponseDto({
                isSuccess: false,
                message: error,
                data: null
            });
        }
    }
 

Это пользовательский сервис.ts

 @Injectable()
export class UserService {

    constructor(
        @InjectModel('User') private readonly userModel: Model<UserDocument>
    ) { }

    public async getMany(query: object): Promise<User[]> {
        const users: User[] = await this.userModel.find(query).exec();
        return users;

    }


    public async getOne(query: object): Promise<User> {
        const user = await this.userModel.findOne(query).exec();
        return user;
    }


    public async deleteOne(query: object): Promise<any> {
        const result = await this.userModel.deleteOne(query).exec();
        if (result.n === 0) {
            throw new HttpException('Not deleted', 400);
        }
        return resu<
    }

    public async deleteMany(query: object): Promise<any> {
        const result = await this.userModel.deleteMany(query).exec();
        if (result.n === 0) {
            throw new HttpException('Not deleted', 400);
        }
        return resu<
    }

    public async updateOne(query: object, user: UserUpdateDto): Promise<User> {
        return await this.userModel.findOneAndUpdate(query, user).exec();
    }

    public async updateMany(query: object, user: UserUpdateDto): Promise<any> {
        return await this.userModel.updateMany(query, user).exec();
    }


    public async add(newUser: UserCreateDto): Promise<User> {
        const user = await new this.userModel(newUser);
        return await user.save();
    }

    public async addRange(newUsers: UserCreateDto[]): Promise<any> {
        return await this.userModel.collection.insertMany(newUsers);
    }

}
 

Результат чванства таков:

 {
  "$__": {
    "strictMode": true,
    "selected": {},
    "getters": {},
    "_id": {
      "_bsontype": "ObjectID",
      "id": {
        "type": "Buffer",
        "data": [
          96,
          171,
          150,
          114,
          131,
          27,
          120,
          44,
          172,
          51,
          211,
          88
        ]
      }
    },
    "wasPopulated": false,
    "activePaths": {
      "paths": {
        "email": "init",
        "userName": "init",
        "password": "init",
        "_id": "init",
        "firstName": "init",
        "lastName": "init",
        "phone": "init",
        "avatar": "init",
        "__v": "init"
      },
      "states": {
        "ignore": {},
        "default": {},
        "init": {
          "_id": true,
          "firstName": true,
          "lastName": true,
          "email": true,
          "phone": true,
          "userName": true,
          "password": true,
          "avatar": true,
          "__v": true
        },
        "modify": {},
        "require": {}
      },
      "stateNames": [
        "require",
        "modify",
        "init",
        "default",
        "ignore"
      ]
    },
    "pathsToScopes": {},
    "cachedRequired": {},
    "$setCalled": [],
    "emitter": {
      "_events": {},
      "_eventsCount": 0,
      "_maxListeners": 0
    },
    "$options": {
      "skipId": true,
      "isNew": false,
      "willInit": true,
      "defaults": true
    }
  },
  "isNew": false,
  "$locals": {},
  "$op": null,
  "_doc": {
    "_id": {
      "_bsontype": "ObjectID",
      "id": {
        "type": "Buffer",
        "data": [
          96,
          171,
          150,
          114,
          131,
          27,
          120,
          44,
          172,
          51,
          211,
          88
        ]
      }
    },
    "firstName": "",
    "lastName": "",
    "email": "ali@gel.com",
    "phone": "",
    "userName": "ali@gel.com",
    "password": "$2b$10$Vp9EYM8fuid.bu2cisp45.QPHdQyPLLlcFeOTPUS98AzUxx3WTekG",
    "avatar": "",
    "__v": 0
  },
  "$init": true
}
 

Есть две проблемы, с которыми я не могу справиться:
1 — Поле пароля все еще находится в ответе. Я хочу исключить это
2 — Объект ответа не является чистым. Есть много областей, которые я не хочу получать.

Ответ, которого я ожидаю, будет:

 { 
isSuccess: true,
message:'ok',
  data: {
    "firstName": "",
    "lastName": "",
    "email": "ali@gel.com",
    "phone": "",
    "userName": "ali@gel.com",
    "avatar": ""
  }
}
 

Комментарии:

1. Преобразование из ClassSerializerInterceptor не сработает, если вы обернете DTO внутри другого DTO, как это

2. Та же проблема! может быть, класс-трансромер не работает с документами мангуста!

Ответ №1:

Вы можете использовать другой пакет и использовать @ExcludeProperty()

 @UseInterceptors(new SanitizeMongooseModelInterceptor())
@Get(':id')
public async getUserById(@Param('id') id: string): Promise<ResponseDto> {
   ...
}