kakasoo

TypeORM, 집계함수(sum, count)와 orderBy 사용하기 본문

프로그래밍/NestJS

TypeORM, 집계함수(sum, count)와 orderBy 사용하기

카카수(kakasoo) 2022. 6. 18. 23:32
반응형

I agree with you. There is a problem here. LoadRelationCountAndMap is mapped, but does not work properly when sorted, and addSelect is not mapped, but can be sorted. Eventually, there is a problem of having to use both.

 

query
    .loadRelationCountAndMap('user.itemCount', 'user.items', 'itemCount') // mapped, but can't be sorted.
    .addSelect((qb) => {
        return qb.select('COUNT(item.id)', 'count').from(ItemEntity, 'item'); // can't be mapped, but can be sorted. ( getMany )
    }, 'count')
    .orderBy('count', 'DESC');

 

I hope that it help other people.

 

addSelect와 loadRelationCountAndMap의 차이

안타깝게도 TypeORM에서는 Repository 패턴으로는 집계함수들을 사용할 수 없다. Entity를 세는 방법은 있지만, Join된 테이블에 대해서는 불가능하고, 그마저도 완벽하지 못하다. 그래서 울며 겨자먹기로 queryBuilder를 사용한 후, loadRelationCountAndMap을 써야 하는데, 이 경우에는 객체에 mapping은 되지만, 이후 로직에서 alias로 잡는 것이 불가능하다. 즉, 추가적인 쿼리문의 작성이 불가능한데, 이로 인해 아래와 같은 문제가 생긴다.

 

  • loadRelationAndCountAndMap으로, 게시글의 댓글을 count 하여 조회.
  • 모든 게시글을 조회하는 것은 DB에 부담이 크기 때문에 페이지네이션으로 구현. ( skip, limit )
  • 여기서 댓글 수를 기준으로 정렬하여 조회할 방법이 없다. ( alias로 지정한 문자열을 통해 추가적인 쿼리 작성이 불가능하기 때문 )

 

반대로 addSelect는 alias를 잡을 수는 있지만, getOne, getMany를 사용할 때 mapping이 안 된다. 따라서, 객체의 매핑과 정렬을 동시에 하고 싶다면, addSelect를 함께 써주어야 한다. 사실, 같은 데이터를 가져오는 것이기 때문에 이 둘을 동시에 사용하는 것은 불필요한 서브 쿼리문을 작성하는 것과 마찬가지지만, 현재 TypeORM에서는 이게 최선으로 보인다.

 

TypeORM의 한계?

아쉽게도, 지금은 TypeORM을 쓰면서 개발자의 창의성이 요구된다. 창의성이 요구된다는 것은, 자유도가 높아 표준이랄 게 없는 상황이거나, 아니면 도리어 자유도가 너무 낮아 개발자들이 직접 해결책을 강구하는 경우다. TypeORM은 후자다. 상용화된 프로그램에 사용하는 데에 지장이랄 것은 없지만, 생태계가 더 발전해야 할 필요성이 느껴진다.

 

 

loadRelationCountAndMap 그냥 쓰지 말자!

 

4. WHERE과 subQuery, COUNT를 조건으로 걸기

const users = await this .createQueryBuilder('user') .withDeleted() .where('user.id = :userId', { userId }) .andWhere((qb) => { // 지금까지 결제한 횟수를 알기 위해 OrderInfo 라는 Entity를 카운트한다. const subQuery = qb .subQuery() .s

kscodebase.tistory.com

 

만약 loadRelationCountAndMap을 버리고 where문에는 서브쿼리를,

count한 값을 프로퍼티로 추가해야 한다면 getRawOne, getRawMany를 쓴다면 이 문제를 해결할 수는 있다.

다만 raw한 방식이라 취향이 조금 갈릴 수는 있겠다.

반응형