알림기능을 구현하던중 알 수 없는 오류에 빠졌다. 쿼리가 'distinctAlias.Cards_card_id'라는 칼럼을 찾지 못한다는 것이다.
알 수 없는 별칭을 찾으려는 TypeORM
정확히 말하면, 이 부분은 알림 기능을 위해 카드의 이름과, 카드에 속한 worker들을 불러올 때 생긴 문제이다. cardRepository에서 직접 불러오는데 왜 저 별칭이 생기는 것일까? 의문인 점은 동일한 코드로 card service 파일에서는 잘 불러와졌다는 것이다.
//카드 제목 조회
const card = await this.cardsRepository.findOne({
where: { cardId },
select: ['title'],
relations: ['workers', 'workers.user']
})
위와 같은 코드인데, 엔티티부터 모듈까지 모두 확인해보았다. 그런데도 계속 적으로 저 오류가 떴고 찾아보던 중, find나 findOne 메서드 사용시 TypeORM이 예상치 못한 별칭을 사용할 수 있다는 점과 이 경우 이러한 오류가 발생할 수 있다는 것이다. 그래서 해결 방법을 찾아보던 중 쿼리 빌더를 알게되었다.
- 쿼리빌더(Query Builder)
쿼리빌더는 무엇일까?
쿼리 빌더(QueryBuilder)는 TypeORM에서 복잡한 쿼리를 작성하고 실행할 수 있도록 하는 도구로, SQL 쿼리를 더 세밀하게 제어할 수 있으며, 다양한 조건과 조인을 포함한 복잡한 쿼리를 쉽게 작성할 수 있다.
이러한 쿼리빌더를 통해 해당 부분을 새로 만들어주었다.
// 카드와 관련된 workers 및 users를 로드
const card = await this.cardsRepository.createQueryBuilder('card')
.leftJoinAndSelect('card.workers', 'worker')
.leftJoinAndSelect('worker.user', 'user')
.where('card.cardId = :cardId', { cardId })
.getOne();
쿼리빌더를 통해 새롭게 만들어준 결과는 성공이었다.
그렇다면 쿼리빌더의 어떤점이 사용했을 때, 정상적으로 작동하게 만들어준 것일까?
1. 정확한 제어
- 쿼리빌더는 생성되는 SQL 쿼리에 대한 더 높은 수준의 제어를 통해 원하는 방식으로 조인 및 선택 작업을 세밀하게 조정할 수 있다고 한다. 그래서 의도하지 않은 쿼리 문제를 방지할 수 있다.
2. 명시적인 조인
- 조인할 테이블과 조건을 명시적으로 설정해 조인 조건 및 선택 필드를 명확하게 지정함으로써
Unknown column
과 같은 오류를 피할 수 있다.
3. 필드 선택의 유연성
.addSelect
를 사용하여 추가적으로 필요한 필드(예:card.title
)를 명시적으로 선택할 수 있다.- TypeORM의
findOne
메서드는 복잡한 조인 및 선택 작업에서 때로 예상치 못한 결과를 가져올 수 있지만, 쿼리빌더는 이를 더 명확하게 처리한다.
그렇다면 언제 쿼리 빌더를 사용해야할까?
우선 내 오류같은 경우, findOne 메서드에서 select 옵션과 relations 옵션을 함께 사용할 때, 특정 필드만 선택하면서도 관계 데이터를 로드하려고 할 때 발생할 수 있었던 문제라고 추측하고있다.
- findOne 사용 상황:
- 단순한 조건으로 특정 레코드를 조회할 때.
- 간단한 관계 로딩이 필요한 경우.
- 코드가 간결하고 읽기 쉬워야 하는 경우.
- 쿼리 빌더(QueryBuilder) 사용 상황:
- 복잡한 조인이나 조건이 필요한 경우.
- 특정 필드만 선택하여 데이터 전송을 최적화해야 하는 경우.
- 서브쿼리가 필요한 복잡한 쿼리를 작성해야 하는 경우.
- SQL 쿼리를 세밀하게 제어해야 하는 경우.
이를 통해 여러테이블을 join해야한다던지, 특정 필드 지정과 관계 데이터를 로드를 동시에 진행하거나하는 상황에서는 쿼리빌더를 사용해야한다는점을 배울 수 있었다. 아직 멀고 먼 typescript의 세계. 이것저것 시도해보며 더욱 많은 것들을 배워나가고 싶다.
'개발 기초 다지기' 카테고리의 다른 글
Linux 명령어 정리 (1) | 2024.07.24 |
---|---|
DB 분할? (0) | 2024.07.22 |
웹소켓 웹 알림 기능 구현(할당받은 멤버에게만) (0) | 2024.07.16 |
댓글/상태변화 알림 기능 구현 (왜 http 요청이 아닌 웹소켓인가?) (0) | 2024.07.12 |
칸반보드 프로젝트 LexoRank 트러블 슈팅 (0) | 2024.07.11 |
댓글