티스토리 뷰

OneToMany, ManyToOne, ManyToMany 를 작성해보자.

OneToMany, ManyToOne

앞서 작성 했던 User에 할일 목록인 task 컬럼을 추가하자.

이는 유저입장에서는 task와 OneToMany 관계이며 Task 입장에서는 ManyToOne 관계이다.

먼저 task.entity.ts 파일을 만들고 아래와 같이 작성했다.

import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'
import { User } from './user.entity'

@Entity()
export class Task {
  @PrimaryGeneratedColumn()
  id: number

  @Column()
  name: string

  @ManyToOne(() => User, (user) => user.task, { onDelete: 'SET NULL' })
  user: User

  constructor(name) {
    this.name = name
  }
}

다음 user.entity.ts 에 다음 코드를 추가했다.

@OneToMany(() => Task, (task) => task.user, { nullable: true })
  task: Task[]

이제 할 일 목록을 추가하는 작업을 추가해보자.

먼저 create-task.dto.ts 를 작성했다.

import { IsString } from 'class-validator'

export class createTaskDto {
  @IsString()
  readonly name: string
}

그 다음 controllerservice 에 task를 추가하는 작업을 추가했다.

/user/task/:id 로 patch요청과 함께 task 작업을 json형태로 보내면

id에 해당하는 유저에 task를 추가한다.

//user.controller.ts
@Patch('task/:id')
  createTask(@Param('id') userId: number, @Body() taskData: createTaskDto) {
    return this.userService.createTask(userId, taskData)
 }

//user.service.ts
async createTask(id: number, taskData: createTaskDto) {
    const user = await this.userRepository.findOne(id, {
      relations: ['task'],
    })
    const task = await this.taskRepository.save(taskData)
    user.task.push(task)
    return await this.userRepository.save(user)
  }

이렇게 작성한 다음 patch요청을 두번정도 보낸다음에 결과를 확인 해 보았다.

{
  "id": 1,
  "name": "j342y2o",
  "gender": "Male",
  "age": 26,
  "carId": null,
  "createdAt": "2021-07-30T07:12:33.535Z",
  "updatedAt": "2021-07-30T07:15:48.277Z",
  "car": null,
  "task": [
    {
      "name": "study",
      "id": 2
    },
    {
      "name": "sleep",
      "id": 3
    }
  ]
}

이렇게 task에 할일이 추가되어 결과가 돌아오는 것을 확인할 수 있다.

ManyToMany

마지막으로 ManyToMany를 작성해 보자.

이번엔 User와 meeting 관계를 작성할 것이다.

유저는 여러개의 meeting을 가질 수 있고, meeting은 여러개의 유저를 가질 수 있다.

먼저 metting.entity.ts 를 만들었다.

import {
  Column,
  Entity,
  JoinColumn,
  ManyToMany,
  OneToOne,
  PrimaryGeneratedColumn,
} from 'typeorm'
import { User } from './user.entity'

@Entity()
export class Meeting {
  @PrimaryGeneratedColumn()
  id: number

  @Column()
  name: string

  @OneToOne(() => User)
  @JoinColumn()
  owner: User

  @ManyToMany(() => User, (user) => user.meetings)
  user: User[]
}

그리고 user.entity.ts 를 수정했다.

@ManyToMany(() => Meeting, (meetings) => meetings.user)
@JoinTable()
meetings: Meeting[]

ManyToMany 관계일 경우 @JoinTable() 을 설정해줘야한다.

@JoinTable() is required for @ManyToMany relations. You must put @JoinTable on one (owning) side of relation.

typeorm 공식문서에서도 이 내용을 말해주고 있다.

이제 meeting을 추가하고 user와 연결해보자.

meetin을 개설하는 방법은 /user/meeting 에 post요청으로 meeting의 name과 owner의 id를 담아서 보내면 된다.

//user.controller.ts
@Post('meeting')
  createMeeting(@Body() MeetingInfo: createMeetingDto) {
    return this.userService.createMeeting(MeetingInfo)
  }

//user.service.ts
async createMeeting(meetingInfo: createMeetingDto) {
    const { owner, name } = meetingInfo
    const user = await this.userRepository.findOne(owner, {
      relations: ['meetings'],
    })
    const meeting = await this.meetingRepository.save({
      name: name,
      owner: user,
    })
    user.meetings.push(meeting)
    await this.userRepository.save(user)
  }

이렇게 코드를 작성하고

{
    "name" : "meeting1",
    "owner" : 1
}

로 POST요청을 보내고 결과를 확인해보았다.

{
  "id": 1,
  "name": "jonyo",
  "gender": "Male",
  "age": 26,
  "carId": null,
  "createdAt": "2021-07-30T08:38:52.268Z",
  "updatedAt": "2021-07-30T08:38:52.268Z",
  "car": null,
  "task": [],
  "meetings": [
    {
      "id": 1,
      "name": "meeting1"
    }
  ]
}

이렇게 meeting정보가 잘 들어간 것을 볼 수 있다.

이제 이렇게 개설된 meeting에 유저를 추가해보자.

/user/meeting/:id 로 patch요청을 보내면서 body에 userId를 담으면 해당 meeting에 대해 유저를 추가하게 된다.

//user.controller.ts
@Patch('meeting/:id')
  addUserToMeeting(@Param('id') meetingId: number, @Body() data: any) {
    this.userService.addUserToMeeting(meetingId, data.userId)
}

//user.service.ts
async addUserToMeeting(meetingId: number, userId: number) {
    const user = await this.userRepository.findOne(userId, {
      relations: ['meetings'],
    })
    const meeting = await this.meetingRepository.findOne(meetingId)
    user.meetings.push(meeting)
    await this.userRepository.save(user)
  }

이제 정상적으로 결과가 잘 나오는지 확인하기 위해 meeting id를 가지고 meeting의 정보를 가져오는 함수를 작성해보자.

//user.controller.ts
@Get('meeting/:id')
  getMeeting(@Param('id') meetingId: number) {
    return this.userService.getMeeting(meetingId)
}

//user.service.ts
async getMeeting(meetingId: number): Promise<Meeting> {
    const meeting = await this.meetingRepository.findOne(meetingId, {
      relations: ['owner', 'user'],
    })
    if (!meeting)
      throw new NotFoundException(`Not found meeting with the id ${meetingId}`)
    return meeting
  }

앞서 생성한 1번 미팅에 대한 정보를 확인하기 위해 /user/meeting/1 로 Get요청을 보내보았다.

{
  "id": 1,
  "name": "meeting1",
  "owner": {
    "id": 1,
    "name": "jonyo",
    "gender": "Male",
    "age": 26,
    "carId": null,
    "createdAt": "2021-07-30T08:38:52.268Z",
    "updatedAt": "2021-07-30T08:38:52.268Z"
  },
  "user": [
    {
      "id": 1,
      "name": "jonyo",
      "gender": "Male",
      "age": 26,
      "carId": null,
      "createdAt": "2021-07-30T08:38:52.268Z",
      "updatedAt": "2021-07-30T08:38:52.268Z"
    },
    {
      "id": 2,
      "name": "jonyo1",
      "gender": "Male",
      "age": 26,
      "carId": null,
      "createdAt": "2021-07-30T08:38:55.502Z",
      "updatedAt": "2021-07-30T08:38:55.502Z"
    }
  ]
}

이런식으로 meeting에 추가된 유저의 정보를 확인할 수 있다.


Nest.js는 확실히 매우 편리하다.

node를 쓰다가 express를 쓰면 매우 편리함을 느낄 수 있는데 nest는 express보다 편리하다.

또 기본적으로 프로젝트의 구조를 잡아주기에 여기서 시키는대로 따라하면 유지보수하기 쉬운 코드를 자동적으로 짤 수 있다.

nest의 가장 기본 중 기본만 다뤄보았는데도 많은 곳에서 편리하다는 것을 느꼈다. 여러가지 기능들을 모듈화 하면서 구조적인 프로젝트를 만들 수 있었다.

typeORM은 처음 사용해보는거라 너무 어려웠다. 아직도 이게 맞는지 헷갈린다. 그래도 타입을 지원한다는 점에서 매우 강력한 도구인 것 같다. 조금 더 숙련된다면 좋을 것 같다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함