Does such a thing exist or do I follow standard Mongoose procedure?
I read the docs, I spent the whole day yesterday for this, but I could only find relative ones that placed the functions inside the service component. This is not effective as if I would like to use a static model function outside of the service component (say, a custom decorator), it wouldn't reach it as DI is private.
I would have created an Issue on Github for documentation request, but I feared I may have overlooked something.
Edit 2: Please do not change the title of the post. "Nest" is not a typo for "best". It is referring to a Node.js framework called Nest.js. (See post tags and referenced documentation link)
Edit: In the MongoDB section of the docs, there's this piece of code:
constructor(@InjectModel(CatSchema) private readonly catModel: Model<Cat>) {}
but specifically, this Model<Cat> part, imports Cat from an interface that extends Mongoose Document interface. Wouldn't it be better if this Cat interface was a class instead which was capable of functions (even after transpilation)?
I use the following approach:
When defining the schema, add static methods to the Mongoose schema:
UserSchema.methods.comparePassword = async function(candidatePassword: string) {
return await bcrypt.compare(candidatePassword, this.password);
};
Also include the method in the object's interface definition:
export interface User {
firstName: string;
...
comparePassword(candidatePassword: string): Promise<boolean>;
}
as well as the UserDocument interface
export interface UserDocument extends User, Document { }
So now my UsersService:
export class UsersService {
constructor(@InjectModel(Schemas.User) private readonly userRepository: Model<UserDocument>,
private readonly walletService: WalletsService,
@Inject(Modules.Logger) private readonly logger: Logger) {}
async findByEmail(email: string): Promise<UserDocument> {
return await this.userRepository.findOne({ email }).select('password');
}
...
}
And to tie it all together, when a user tries to log in, the Auth service retrieves a user object by id, and invokes that user object's instance method of comparePassword:
@Injectable()
export class AuthService {
constructor(
private readonly usersService: UsersService,
private readonly jwtService: JwtService,
) { }
async signIn({ email, password }: SignInDto): Promise<LoginResponse> {
const user = await this.usersService.findByEmail(email);
if (!user) { throw new UnauthorizedException('Invalid Username or Password'); }
if (await user.comparePassword(password)) {
const tokenPayload: JwtPayload = { userId: user.id };
const token = this.jwtService.sign(tokenPayload);
return ({ token, userId: user.id, status: LoginStatus.success });
} else {
throw new UnauthorizedException('Invalid Username or Password');
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With