[TypeORM] subQuery 사용하여 정보 가져오기

pagination이 적용된 GET 메소드 API를 구성할 때, 주로 createQueryBuilder()를 활용하여 쿼리를 구성하고, .skip()과 .take()를 통해 pagination을 적용시킨다. 만약 다른 테이블에서 특정 칼럼의 값을 가져와 해당 값을 통해 현재 createQueryBuilder가 작동하는 테이블에서 필터링을 통해 값을 가져와야되면, TypeORM 공식 문서에 나와 있는 것과 같이 .getQuery(), .getParameter()를 사용하여 subQuery를 구성할 수 있다.

 

TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server,

 

typeorm.io

내가 사용한 방법은 위의 문서에서 하나의 QueryBuilder()를 두 개로 나눠서 SQL 생성시 합치는 것이다.

//story.service.ts

async findArtistStory(
    page: number,
    limit: number,
    categoryIds: number[],
  ): Promise<Paginated<Story>> {
  	
    //User Table에서 ROLE을 기반으로 조건을 충족한 유저의 id만 가져온다.
    const artists = await this.connection
      .createQueryBuilder(User, 'user')
      .where('user.role = :role', { role: Role.ARTIST })
      .select(['id']);
	
    //Story Table에서 CategoryStory라는 JOIN 용도의 Table을 join 시켜서 CategoryId를 불러온다.
    const filter = await this.repository
      .createQueryBuilder('story')
      .leftJoin(
        CategoryStory,
        'categoryStory',
        'categoryStory.storyId = story.id',
      )
      .where('story.userId IN(' + artists.getQuery() + ')')
      .setParameters(artists.getParameters());
    if (categoryIds.length > 0 && categoryIds[0]) {
      filter.andWhere('categoryStory.categoryId IN(:...categoryId)', {
        categoryIds,
      });
    }
    
    // Pagination 적용 부분
    filter.skip((page - 1) * limit).take(Math.min(limit, 1000));
    const [items, total] = await filter.getManyAndCount(); 
    return { items, total };
  }