[NestJS] - 14. TypeORM JOIN과 QueryBuilder

2023. 2. 25. 04:33
반응형

이전 포스팅에서 TypeORM을 이용해 관련 테이블들을 외래키 연결 및 생성하는 코드를 작성해보았다.

이번에는 SQL의 Join에 해당하는 TypeORM 질의를 작성해보려고 한다.

 

 


Relations

    const result = await this.productRepository.find({
      relations: ['productCategory', 'productTags'],
    });

단순하게 Left Join하여 모든 컬럼들을 가져오려면 relations를 작성해주면 된다.

인수로는 Join하려는 모든 릴레이션 테이블들을 리스트로 작성한다.

 

 

SELECT 
`Product`.`id` AS `Product_id`, 
`Product`.`name` AS `Product_name`, 
`Product`.`description` AS `Product_description`, 
`Product`.`price` AS `Product_price`,
`Product`.`isSoldOut` AS `Product_isSoldOut`, 
`Product`.`deletedAt` AS `Product_deletedAt`, 
`Product`.`updatedAt` AS `Product_updatedAt`, 
`Product`.`productSalesLocationId` AS `Product_productSalesLocationId`, 
`Product`.`productCategoryId` AS `Product_productCategoryId`, 
`Product`.`userId` AS `Product_userId`, 
`Product__productCategory`.`id` AS `Product__productCategory_id`, 
`Product__productCategory`.`name` AS `Product__productCategory_name`, 
`Product__productTags`.`id` AS `Product__productTags_id`, 
`Product__productTags`.`name` AS `Product__productTags_name` 
FROM `product` `Product` 
LEFT JOIN `product_category` `Product__productCategory` 
ON `Product__productCategory`.`id`=`Product`.`productCategoryId`  
LEFT JOIN `product_product_tags_product_tag` `Product_Product__productTags` 
ON `Product_Product__productTags`.`productId`=`Product`.`id` 
LEFT JOIN `product_tag` `Product__productTags` 
ON `Product__productTags`.`id`=`Product_Product__productTags`.`productTagId` 
WHERE `Product`.`deletedAt` IS NULL

다음의 쿼리와 동일하다.

 

 

 

 

 


Join

  async findAll(): Promise<Product[]> {
    const result = await this.productRepository.find({
      join: {
        alias: 'p',
        leftJoinAndSelect: {
          id: 'p.productCategory'
        }, 
      },
      
    });
    return result;
  }

다음과 같이 Alias를 지정하여 Join Select 할 수도 있다.

 

 

 


QueryBuilder

위처럼 Join하여 사용하는 방법을 TypeORM에서 제공하기는 하지만 Select 시 모든 컬럼을 선택해야 하는 점,  Multiple한 테이블을 Join하기 까다로운 점 등이 문제가 있다.

따라서 TypeORM에서 QueryBuilder라는 기능을 제공한다.

제공하는 기능이 많으며 웬만한 SQL문을 작성할 수 있으므로 Select하는 경우 QueryBuilder를 이용하는 것이 좋다.

 

 

 

 


 

QueryBuilder : JoinAndSelect

 

    const result = await this.productRepository
      .createQueryBuilder('p')
      .leftJoinAndSelect('p.productCategory', 'pc')
      .leftJoinAndSelect('p.productTags', 'pt')
      .where('p.id = :id and pc.name = pt.name', { id: id })
      .getOne();
  • createQueryBuilder()를 통해 쿼리를 생성하고 Alias를 지정한다.
  • leftJoinAndSelect은 Join하면서 대상 테이블의 모든 컬럼을 Select한다. Join할 Key 컬럼과 Alias를 지정한다.
  • where문에는 조건을 입력하고, 파라미터는 :param 의 형태로 입력할 수 있다.
  • getOne(), getMany()등을 이용해서 결과를 얻어온다.

 

SELECT `p`.`id` AS `p_id`, `p`.`name` AS `p_name`, 
`p`.`description` AS `p_description`, 
`p`.`price` AS `p_price`, 
`p`.`isSoldOut` AS `p_isSoldOut`,
`p`.`deletedAt` AS `p_deletedAt`, 
`p`.`updatedAt` AS `p_updatedAt`, 
`p`.`productSalesLocationId` AS `p_productSalesLocationId`,
`p`.`productCategoryId` AS `p_productCategoryId`,
`p`.`userId` AS `p_userId`, 
`pc`.`id` AS `pc_id`, 
`pc`.`name` AS `pc_name`,
`pt`.`id` AS `pt_id`,
`pt`.`name` AS `pt_name` 
FROM `product` `p` 
LEFT JOIN `product_category` `pc` 
ON `pc`.`id`=`p`.`productCategoryId`  
LEFT JOIN `product_product_tags_product_tag` `p_pt` 
ON `p_pt`.`productId`=`p`.`id` 
LEFT JOIN `product_tag` `pt` 
ON `pt`.`id`=`p_pt`.`productTagId` 
WHERE ( `p`.`id` = ? and `pc`.`name` = `pt`.`name` ) 
AND ( `p`.`deletedAt` IS NULL ) -- PARAMETERS: ["18"]

다음과 같은 쿼리가 실행된다.

 

 


QueryBuilder : Join

 

    const result = await this.productRepository
      .createQueryBuilder('p')
      .select(['p.id', 'p.name', 'p.price', 'pc.name', 'pt.name'])
      .leftJoin('p.productCategory', 'pc')
      .leftJoin('p.productTags', 'pt')
      .where('p.id = :id and pc.name = pt.name', { id: id })
      .getOne();
  • createQueryBuilder()를 통해 쿼리를 생성하고 Alias를 지정한다.
  • leftJoin은 Join하면서 대상 테이블을 Select하지 않는다. Join할 컬럼과 Alias를 지정한다.
  • select()에 Select할 컬럼들을 선택적으로 작성할 수 있다.

 

SELECT `p`.`id` AS `p_id`,
`p`.`name` AS `p_name`, 
`p`.`price` AS `p_price`, 
`pc`.`name` AS `pc_name`, 
`pc`.`id` AS `pc_id`, 
`pt`.`name` AS `pt_name`, 
`pt`.`id` AS `pt_id` 
FROM `product` `p` 
LEFT JOIN `product_category` `pc` 
ON `pc`.`id`=`p`.`productCategoryId`  
LEFT JOIN `product_product_tags_product_tag` `p_pt` 
ON `p_pt`.`productId`=`p`.`id` 
LEFT JOIN `product_tag` `pt` 
ON `pt`.`id`=`p_pt`.`productTagId` 
WHERE ( `p`.`id` = ? and `pc`.`name` = `pt`.`name` ) 
AND ( `p`.`deletedAt` IS NULL ) -- PARAMETERS: ["18"]

다음과 같이 모든 컬럼을 선택하지 않고 원하는 컬럼만을 선택할 수 있다.

 


QueryBuilder에 대한 기능들은 공식 문서를 참고하면 언급한 내용 외에 많은 Example을 제공하고 있다.

https://typeorm.io/select-query-builder#joining-relations

 

 

 

 

 

 


해당 강의를 들으면서 학습한 내용을 바탕으로 저만의 프로젝트를 만드는 과정을 기록하여 남기는 것을 목표로 하고 있습니다.

주관적인 생각이 들어가 있을 수 있으므로 혹시 틀린 내용이 있다면 피드백 부탁드립니다.

https://www.inflearn.com/course/%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B3%A0%EB%86%8D%EC%B6%95-%EC%BD%94%EC%8A%A4/dashboard

 

[인프런x코드캠프] 부트캠프에서 만든 고농축 백엔드 코스 - 인프런 | 강의

코딩과 사랑에 빠져버린 8년차 풀스택 개발자 Captain의 사심이 가득 담긴 커리큘럼이에요. 백엔드의 모든 것을 다 알려주고 싶은 Captain의 마음이 녹아있죠! 이 강의를 듣다보면 '이렇게까지 알려

www.inflearn.com

반응형

BELATED ARTICLES

more