Chào mừng các bạn trở lại với series tutorial Nestjs của mình.
Nói chung là học cái nestjs này nó cũng đơn giản nhưng mà "people make it complicated" nên mình sẽ giúp em các bạn cảm thấy enjoy cái framework này 😂 😂 😂 - theo danh ca Chipu
Index series
- Giới thiệu về setup repository + typeorm.
- Xác thực người dùng trong Nestjs sử dụng Passport JWT.
- Tiếp tục series mình cùng các bạn sẽ tìm hiểu vể Relationship trong Nestjs + Typeorm. Bắt đầu nhé
1. Setting base
-
Ở bài viết về setup repository + typeorm mình đã setting rất chi tiết rồi. mọi người có thể tham khảo lại bài viết tại đây
-
Cụ thể: ở đây mình sẽ chỉ lấy ra thông tin user bằng id gửi lên function findById($id)
Trong user.service.ts :
import { UsersRepository } from './users.repository'; ... @Injectable() export class UsersService { constructor( @InjectRepository(UsersRepository) private usersRepository: UsersRepository, ) {} async findById( id: number, relations: string[] = [], throwsException = false, ): Promise<UserEntity> { return await this.usersRepository.getEntityById( id, relations, throwsException, ); } }
Trong user.repository.ts :
import { UsersService } from './users.service'; ... @Injectable() export class UsersService { constructor( @InjectRepository(UsersRepository) private usersRepository: UsersRepository, ) {} async findById( id: number, relations: string[] = [], throwsException = false, ): Promise<UserEntity> { return await this.usersRepository.getEntityById( id, relations, throwsException, ); } }
2. One-To-One
-
Định nghĩa table
users table :id name email password int increment varchar varchar varchar profiles table
id user_id avatar address phone gender int increment int varchar varchar varchar varchar -
Define relationship in entity Định nghĩa user.entity.ts :
import { IUser } from '../interfaces/user.interface'; ... @Entity({ name: 'users' }) export class User implements IUser { @PrimaryGeneratedColumn() id: string; @Column({ unique: true, length: 255 }) email: string; @Column({ name: 'password', length: 255 }) password: string; @CreateDateColumn({ name: 'created_at', type: 'timestamp', nullable: true }) createdAt: Date; @UpdateDateColumn({ name: 'updated_at', type: 'timestamp', nullable: true }) updatedAt: Date; // define relationship with profiles table @OneToOne(() => Profile, (profile) => profile.user) profile: Profile; }
Định nghĩa profile.entity.ts :
import { User } from './entities/user.entity'; ... @EntityRepository(User) export class UsersRepository { ... //function get user by id and relationship async getEntityById( id: number, relations: string[] = [], ): Promise<UserEntity | null> { return await this.findOne({ where: { id }, relations, }).then((entity) => { if (!entity) { return Promise.reject(new NotFoundException('Model not found')); } return Promise.resolve(entity ? this.transform(entity) : null); }); } transform(model: User): UserEntity { const transformOptions = {}; return plainToClass( UserEntity, classToPlain(model, transformOptions), transformOptions, ); }
-
Get data User with Profile
Trong user.controller.ts :
import { UsersService } from './users.service'; ... @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} ... @Get('conversation/:id') async userConversation(@Param() params): Promise<UserEntity> { const user = await this.usersService.findById(params.id, [ 'profile', ]); this.throwUserNotFound(user); return user; } ... }
còn đây sẽ là response
{ "id": "13", "name": "duong", "email": "xuanduong.kma@gmail.com", "password": "$2b$12$JDj6D0RIjpGdd4tAGO/BMOqUxmq.7tEGIvWHtJfbm6MfxIeXyBrGW", "createdAt": "2021-10-10T06:56:06.000Z", "updatedAt": "2021-10-10T06:56:06.000Z", "profile": { "id": "2", "user_id": "13", "avatar": null, "phone": "+84999999999", "createdAt": "2021-10-16T10:51:49.000Z", "updatedAt": "2021-10-16T10:51:49.000Z" }, }
3. One-To-Many
-
Định nghĩa table
users table :id name email password int increment varchar varchar varchar messages table
id user_id conversation_id message int increment int int varchar -
Define relationship in entity
Định nghĩa user.entity.ts :
import { IUser } from '../interfaces/user.interface'; ... @Entity({ name: 'users' }) export class User implements IUser { ... @OneToMany(() => Message, (message) => message.user) messages?: Message[]; }
Định nghĩa messages.entity.ts
import { IUser } from '../interfaces/user.interface'; ... @Entity({ name: 'messages' }) export class Message implements IMessage { ... @ManyToOne(() => User, (user) => user.messages) @JoinColumn({ name: 'user_id' }) user?: User; }
-
Get data User with Profile
Trong user.controller.ts :
import { UsersService } from './users.service'; ... @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} ... @Get('conversation/:id') async userConversation(@Param() params): Promise<UserEntity> { const user = await this.usersService.findById(params.id, [ 'messages', ]); this.throwUserNotFound(user); return user; } ... }
còn đây sẽ là response
{ "id": "13", "name": "duong", "email": "xuanduong.kma@gmail.com", "messages": [ { "id": "1", "conversation_id": "1", "user_id": "12", "message": "hello xuan duong 2", }, { "id": "2", "conversation_id": "1", "user_id": "12", "message": "hello xuan duong 2", }, ] }
4. Many-To-Many
-
Định nghĩa table
users table :id name email password int increment varchar varchar varchar conversations table :
id title description .... int increment varchar varchar varchar user_conversation table
id user_id conversation_id int int int -
Define relationship in entity
Định nghĩa user.entity.ts :
@Entity({ name: 'users' }) export class User implements IUser { ... @ManyToMany(() => Conversation, (conversations) => conversations.users) @JoinTable({ name: 'user_conversation', joinColumn: { name: 'user_id', referencedColumnName: 'id' }, inverseJoinColumn: { name: 'conversation_id' }, }) conversations: Conversation[]; }
conversation.entity.ts :
@Entity({ name: 'conversations' }) export class Conversation implements IConversation { ... @ManyToMany(() => User, (users) => users.conversations) @JoinTable({ name: 'user_conversation', joinColumn: { name: 'conversation_id', referencedColumnName: 'id' }, inverseJoinColumn: { name: 'user_id' }, }) users: User[]; }
- Get data User with Profile
Trong user.controller.ts :
import { UsersService } from './users.service'; ... @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} ... @Get('conversation/:id') async userConversation(@Param() params): Promise<UserEntity> { const user = await this.usersService.findById(params.id, [ 'conversations', 'conversations.messages', // lấy ra luôn các message trong converstion => nhớ định nghĩa relationship nhé ]); this.throwUserNotFound(user); return user; } ... }
5. Kết luận
-
Qua bài viết này mình đã giới thiệu cho các bạn relationship trong typeorm. nếu có khó khắn hoặc thắc mặc đừng ngại ngần comment ở dưới, Nếu bài viết hay và hữu ích thì cho mình xin 1 upvote.
-
Từ cấu trúc bảng mình đã xây dựn ở trên , ở bài tiếp theo mình sẽ giới thiệu với các bạn về chat realtime sử dụng :
Server: Nestjs + socket.io
Client: React + Redux saga
Thank you!