typeorm을 이용한 where in 쿼리 사용하기

dev Aug 12, 2019

이직하고 새로운 환경에 적응 중인데, 타입스크립트도 적응 대상 중 하나이다. 익숙하지 않으니 작업을 하다가 속도가 떨어지고, 제대로 알고 쓰지도 못하는 거 같아 따로 타입스크립트 공부를 하기로 마음먹었다. 타입스크립트에 익숙해지기 위해 두 가지 정도를 하고 있는데 다음과 같다.

  1. 타입스크립트 레퍼런스 핸드북 번역하기
  2. 현업에서 마주칠 수 있는 다양한 상황을 API로 만들어 보기

1번은 번역하면 머릿속으로 내용이 이해는 되지만, 자연스러운 번역을 하려고 노력하다 보니 한편마다 시간이 제법 걸린다. 그래서 2번을 주로 진행하고 1번은 하루에 한 줄이라도 번역하자는 생각으로 진행하고 있다. 그 생각의 첫 번째로 오늘은 타입스크립트에서 typeorm을 이용한 where in 쿼리 사용하기라는 주제로 글을 쓰려 한다.

아래의 예제는 node(express), mysql, typescript(3.5.2)을 사용했으며, 그중에서도 typestack에 있는 routing-controllers, typedi 그리고 typeorm, typeorm-typedi-extensions 등의 패키지를 사용했다.

프로젝트 구조

기본적인 프로젝트 구조는 다음과 같다. 다른 프레임워크에서 많이 사용하는 controllers, services, repositories, models, entities 구조로 되어 있다.

오늘은 쿼리 사용법에 대한 글이기 때문에 다른 부분은 생략하고 Repository만 살펴본다.

where in 쿼리

typeorm에서 where in 쿼리를 사용하는 방법은 두 가지가 있으며 다음과 같다.

Query Builder에 있는 whereInIds 사용하기

public async getUsersById(request: GetUserRequest): Promise<User[] | undefined> {
        return await this.userRepository.createQueryBuilder()
        .whereInIds(request.ids)
        .getMany()
}


where문에서 raw 쿼리 사용하기

public async getUsersById(request: GetUserRequest): Promise<User[] | undefined> {
        return await this.userRepository.createQueryBuilder()
        .where("id IN (:id)", { id: request.ids })
        .getMany()
}


결과

[
  {
    "id": 1,
    "uuid": "",
    "name": "",
    "regtime": "2017-07-26T10:49:10.000Z"
  },
  {
    "id": 2,
    "uuid": "",
    "name": "",
    "regtime": "2017-07-28T15:34:32.000Z"
  }
] 

두 개의 결과는 위처럼 똑같이 출력된다. 하지만 동작하는 API를 살펴보던 중 이상한 점을 발견했다. 같은 where in 쿼리를 사용했지만, 내부에서 동작하는 쿼리가 달랐다. 실제로 동작하는 쿼리는 다음과 같다.

Query Builder에 있는 whereInIds의 동작 방식

query: 
SELECT User.id AS User_id, User.uuid AS User_uuid, User.name AS User_name, User.regtime AS User_regtime
FROM user User 
WHERE (User.id = ?) OR (User.id = ?) -- PARAMETERS: ["1","2"]

whereInIds는 내부적으로 OR을 사용해서 동작한다.

where문에서 raw 쿼리의 동작 방식

query: 
SELECT `User`.`id` AS `User_id`, `User`.`uuid` AS `User_uuid`, `User`.`name` AS `User_name`, `User`.`regtime` AS `User_regtime` 
FROM `user` `User` WHERE id IN (?) -- PARAMETERS: [["1","2"]]

raw 쿼리는 위에서 명시한 바와 같이 IN 쿼리를 사용해서 동작한다.

이처럼 같은 동작을 기대하고 사용하는 사용자와는 다르게 내부에서는 위와 같이 동작한다. IN, OR 쿼리 성능에 대한 이야기도 많이 있기 때문에 상황에 알맞은 쿼리를 선택해서 사용하면 좋을 거 같다.

cherrypick

체리픽이라는 단어 본연의 뜻은 안 좋은 의미이지만 저는 트렌디하고 많은 기술을 공부하고 내 거로 만들자는 뜻을 가지고 사용하고 있습니다.