QueryBuilder .leftJoin사용시 원하는 칼럼만 SELECT하기

QueryBuilder를 사용하여 JOIN 쿼리가 포함된 쿼리문을 작성하다보면 주로 .leftJoinAndSelect 메소드를 사용한다. 

.leftJoinAndSelect를 사용하면 하나하나 칼럼을 체크할 필요가 없고, 코드 가시성적인 면에서는 장점이 있었지만, 모든 칼럼을 Select해오다보니 성능적인 면에서 필요한 칼럼만을 가져오는 쿼리에 비해 상대적으로 메모리 사용량이 많은 문제점 또한 존재한다.

 

작성하던 코드 중 JOIN을 3개의 테이블에 걸쳐 쿼리를 날려야되는 API가 있었는데 모든 칼럼을 SELECT해올 필요가 없어서 조금 코드 가시성은 떨어져도 .leftJoinAndSelect의 사용을 지양하고, .leftJoin과 .select, .addSelect를 사용하여 작성하였다.

 

async findNewsLetterSubmitters(id: number) {
    const newsletter = await this.repository
      .createQueryBuilder('newsletter')
      .where('newsletter.id = :id', { id: id })
      .select('newsletter.id')
      .addSelect('newsletter.title')
      .addSelect('newsletter.content')
      .addSelect('newsletter.createdAt')
      .addSelect('newsletter.updatedAt')
      .addSelect('newsletter.surveyContent')
      .leftJoin(
        'newsletter.studentNewsletters',
        'studentNewsLetters',
        'studentNewsLetters.newsletterId = newsletter.id',
      )
      .addSelect('studentNewsLetters.id')
      .addSelect('studentNewsLetters.isSubmitted')
      .addSelect('studentNewsLetters.studentGradeKlass')
      .addSelect('studentNewsLetters.studentNumber')
      .leftJoin(User, 'student', 'studentNewsLetters.studentId = student.id')
      .addSelect('student.name')
      .getOne();
    return { newsletter };
  }

1차적으로 .leftJoin이전을 살펴보면 newsLetter 테이블에서 API에서 파라미터로 전달받은 id값으로 조회하여 조회된 1개의 newsLetter의 row에 대해 칼럼명이 'id', 'title', 'content', 'createdAt', 'updateAt', 'surveyContent'를 SELECT하였다.

 

.leftJoin을 통해 studentNewsLetters 테이블에서 newLetterId가 위에서 SELECT해온 newsletter의 id값과 같은 경우만 JOIN을 해서 위의 조건을 충족한 row의 'id', 'isSubmitted', 'studentGradeKlass', 'studentNumber'를 SELECT한다.

 

studentNewsLetters 테이블의 studentId와 User 테이블의 id값이 같은 경우를 JOIN해서 유저의 name 칼럼 정보를 SELECT한다.

실제로 해당 쿼리를 로그 찍어보면 아래와 같이 출력된다.

필요한 칼럼만 SELECT해옴을 알 수 있다.

 

2022.01.24 업데이트)

위의 코드처럼 칼럼명을 하나씩 select(), .addSelect()를 할 필요없이 아래처럼 리스트의 형태로 칼럼명을 관리해도 된다.

async findNewsLetterSubmitters(id: number) {
    const newsletter = await this.repository
      .createQueryBuilder('newsletter')
      .where('newsletter.id = :id', { id: id })
      .select([
        'newsletter.id',
        'newsletter.title',
        'newsletter.content',
        'newsletter.createdAt',
        'newsletter.updatedAt',
        'newsletter.surveyContent',
      ])
      .leftJoin(
        'newsletter.studentNewsletters',
        'studentNewsLetters',
        'studentNewsLetters.newsletterId = newsletter.id',
      )
      .addSelect([
        'studentNewsLetters.id',
        'studentNewsLetters.isSubmitted',
        'studentNewsLetters.studentGradeKlass',
        'studentNewsLetters.studentNumber',
      ])
      .leftJoin(User, 'student', 'studentNewsLetters.studentId = student.id')
      .addSelect('student.name')
      .getOne();
    return { newsletter };
  }