웹/백엔드

[TypeORM] 커스텀 값 entity에 매핑하여 들고오는 법

이민훈 2024. 2. 7. 00:38

아래와 같은 유저 테이블이 있습니다.

 

@Entity("users")
export class User extends IdEntity implements UserScheme {
  @Column()
  password: string;

  @Column({ unique: true })
  social_id: string;

  @Column()
  name: string;

  @Column()
  sex: boolean;

  @Column()
  phone: string;

  @Column({ unique: true })
  email: string;

  @OneToMany(() => UserInClub, (userInClub) => userInClub.user, {
    cascade: true,
  })
  public clubs: UserInClub[];

  @OneToMany(() => Feed, (feed) => feed.user, {
    cascade: true,
  })
  public feeds: Feed[];

  @OneToMany(() => Comment, (comment) => comment.user, {
    cascade: true,
  })
  public comments: Comment[];
}

 

이때, entity의 속성들 외에 다른 값들을 가져오고 싶을 수 있습니다.

 

예를 들어, user와 club은 N:N 관계입니다.

 

users_in_clubs라는 엔티티에서 role과 exp만 가져와서

 

유저 엔티티에 병합하여 내려주는 것이 깔끔해 보입니다.

 

@Entity("users_in_clubs")
export class UserInClub extends TimesEntity implements UserInClubScheme {
  @PrimaryColumn()
  user_id: number;

  @PrimaryColumn()
  club_id: number;

  @Column()
  role: Role = Role.Pending;

  @Column()
  exp: number = 0;

  @ManyToOne(() => User, (user) => user.clubs, {
    cascade: false,
  })
  @JoinColumn({ name: "user_id" })
  user: User;

  @ManyToOne(() => Club, (club) => club.users, {
    cascade: false,
  })
  @JoinColumn({ name: "club_id" })
  club: Club;
}

 

아래는 club에 속한 모든 유저들을 불러오는 코드입니다.

 

  findAllByClub = async (clubId: number) => {
    try {
      const users = await this._repository
        .createQueryBuilder("user")
        .leftJoin("user.clubs", "club", "club.deleted_at IS NULL")
        .addSelect("club.role", "user_role")
        .addSelect("club.exp", "user_exp")
        .where("club.club_id = :clubId", { clubId })
        .andWhere("user.deleted_at IS NULL")
        .getMany();
      return users.map((user) => UserConverter.toDto(user));
    } catch (err) {
      console.log(err);
      throw Errors.InternalServerError;
    }
  };

 

하지만 실제 매핑되어 내려오는 값은 아래 형태의 json입니다.

 

{
    "status": 200,
    "code": 20000,
    "data": [
        {
            "created_at": "2024-02-06T15:02:11.239Z",
            "updated_at": "2024-02-06T15:02:11.239Z",
            "deleted_at": null,
            "id": 1,
            "social_id": "social1",
            "name": "minhoon1",
            "sex": true,
            "phone": "01012341234",
            "email": "minhoon1@naver.com",
            "clubs": []
        }
    ],
    "message": "해당 클럽의 유저들을 불러왔습니다."
}

 

role과 exp는 사라지고 없습니다.

 

db에서 반환된 결과를 엔티티에 매핑하는 과정 중에, role과 exp는 user entity에 존재하지 않기 때문에 그렇습니다.

 

아래와 같이 user entity에 role, exp를 column으로 추가하고, select, insert 옵션을 false로 주어,

 

select 쿼리시 해당 프로퍼티들을 db에 조회, 삽입하지 않도록 합니다. (entity 매핑용으로만 사용)

 

@Entity("users")
export class User extends IdEntity implements UserScheme {
  @Column()
  password: string;

  @Column({ unique: true })
  social_id: string;

  @Column()
  name: string;

  @Column()
  sex: boolean;

  @Column()
  phone: string;

  @Column({ unique: true })
  email: string;

  @OneToMany(() => UserInClub, (userInClub) => userInClub.user, {
    cascade: true,
  })
  public clubs: UserInClub[];

  @OneToMany(() => Feed, (feed) => feed.user, {
    cascade: true,
  })
  public feeds: Feed[];

  @OneToMany(() => Comment, (comment) => comment.user, {
    cascade: true,
  })
  public comments: Comment[];

  @Column({
    enum: Role,
    select: false,
    insert: false,
    readonly: true,
    nullable: true,
  })
  public role: Role;

  @Column({ select: false, insert: false, readonly: true, nullable: true })
  public exp: number;
}

 

동일한 api를 호출해 봤을 때, 원하는 응답을 확인할 수 있습니다.

 

addSelect시에, 꼭 아래와 같이, table 이름을 column 이름 앞에 붙여줘야 합니다.

 

아니면 제대로 매핑이 되지 않습니다.

 

        .addSelect("club.role", "user_role")
        .addSelect("club.exp", "user_exp")

 

 

{
    "status": 200,
    "code": 20000,
    "data": [
        {
            "created_at": "2024-02-06T15:02:11.239Z",
            "updated_at": "2024-02-06T15:02:11.239Z",
            "deleted_at": null,
            "id": 1,
            "social_id": "social1",
            "name": "minhoon1",
            "sex": true,
            "phone": "01012341234",
            "email": "minhoon1@naver.com",
            "role": "admin",
            "exp": 0,
            "clubs": []
        }
    ],
    "message": "해당 클럽의 유저들을 불러왔습니다."
}