Node Knex
Knex - Query Builder
Knex 인스턴스 생성
Knex를 이용해 MySQL 서버에 접속하기 위해서는 일단 아래와 같이 Knex 인스턴스를 만들어야 합니다.
1 | module.exports = require('knex')({ |
확인방법
1 | $ node |
Connection Pool
Knex 인스턴스를 생성하면 connection pool이 만들어집니다. 한 번에 여러 커넥션을 맺어 놓는다는 의미. 그래서 해당 커넥션을 이용합니다.
인스턴스 생성 시 별도의 옵션을 주지 않는다면 커넥션 풀은 2개의 커넥션으로 시작하며, 필요에 의해 10개까지 늘어날 수 있습니다. 자세한 설정은 공식문서를
Knex를 이용한 쿼리 수행
이제부터 Knex 인스턴스를 이용해 쿼리를 날릴 수 있습니다.
주의!
레코드가 수 십만 개 이상인 경우에는 결과를 받아오는 데 시간이 오래 걸리니 꼭 limit 메소드를 사용해주세요.
1 | knex('salaries').limit(3).then(console.log) |
Knex 인스턴스는 메소드 체이닝
방식으로 사용하도록 만들어져 있습니다. 아래와 같이 메소드를 계속 이어붙이는 방식으로 쿼리를 빌드합니다.
1 | // 1위부터 10위까지의 최고 연봉자의 연봉과 first_name을 출력합니다. |
Knex 인스턴스는 표준 Promise가 아니라 자체 Promise 구현을 사용합니다.
이 구현의 특이한 점은 then 메소드를 호출하기 전까지는 SQL을 실행시키지 않는다는 것입니다.
위 성질을 이용해 then 메소드를 호출하지 않은 채로 toString 메소드를 호출하면, 쿼리를 실행시키기 전에 쿼리 빌더가 어떤 쿼리를 생성하는지 알 수 있습니다
.
1 | knex('salaries').limit(3).toString() |
없는 테이블을 써도 생성은 된다. 그러나 실행은 안된다 꼭 실행시에 뒤에 .then을 해줘야한다.
SELECT
select 메소드를 사용하면 원하는 컬럼만을 불러올 수 있습니다.
1 | knex('salaries') |
실제로 쿼리를 실행하면 아래와 같은 결과를 반환합니다.
1 | knex('salaries') |
select
메소드의 인자로 넘기는 문자열 뒤에 as를 붙여서, 반환되는 객체들의 속성 이름을 바꿀 수 있습니다.
1 | knex('salaries') |
distinct 메소드를 사용해 중복 제거를 할 수 있습니다.
1 | knex('employees') |
WHERE
where 메소드를 이용해 WHERE 구문을 빌드할 수 있습니다.
1 | knex('salaries') |
아래와 같이 연산자를 사용할 수도 있습니다.
1 | knex('salaries') |
AND
연산자를 사용하기 위해 where
메소드를 여러 번 사용하거나, andWhere
메소드를 사용할 수 있습니다.
1 | knex('salaries') |
또는 where
메소드에 객체를 넘길 수도 있습니다.
1 | knex('employees') |
NOT
연산자를 사용하기 위해서 whereNot
메소드를 사용합니다.
1 | knex('salaries') |
OR
연산자를 사용하기 위해 orWhere
메소드를 사용할 수 있습니다. 또한 연산이 복잡한 경우에는 함수를 인자로 넘겨서 여러 where의 결합을 나타낼 수 있습니다.
orWhere은 where와 같지만 or로 연결해주는 역할을 한다.
1 | knex('salaries') |
- 이 안에서는
errow function을 사용할 수 없다
why?this의 성격때문이다.
- error function에서 this는 한번 정해지면 바꿀수 없기 때문이다.
그 밖에 아래와 같은 메소드들이 있습니다.
- whereIn
- whereNotIn
- whereNull
- whereNotNull
- whereExists
- whereNotExists
- whereBetween
- whereNotBetween
- andWhereNot
- orWhereNot
자세한 사용법은 공식 문서를 참고해주세요.
INSERT
1 | knex('employees') |
UPDATE
1 | knex('employees') |
DELETE
1 | knex('employees') |
DELETE, UPDATE는 where절을 사용하지 않는다면 전체가 업데이트 or 삭제가 되니 꼭 where절을 사용해야한다.
ORDER BY
orderBy
메소드를 사용해서 ORDER BY 구문을 빌드할 수 있습니다.
1 | knex('employees') |
LIMIT, OFFSET
limit
, offset
메소드를 사용해서 각각 LIMIT, OFFSET 구문을 빌드할 수 있습니다.
- limit : 위에서부터 개수만큼
- offset : 100개를 건너뛰고나서부터
1 | knex('employees') |
집계함수
Knex 인스턴스의 count
, max
, min
, sum
, avg
등의 메소드를 통해 집계함수를 빌드할 수 있습니다.
1 | knex('salaries') |
집계함수의 인자로 넘기는 문자열 뒤에 as를
붙여서, 반환되는 객체들의 속성 이름을 바꿀 수 있습니다.
1 | knex('salaries') |
GROUP BY & HAVING
groupBy
메소드를 통해 GROUP BY
구문을 빌드할 수 있습니다. 보통 위에서 다뤘던 집계함수와 함께 사용합니다.
1 | knex('salaries') |
having
메소드를 통해 HAVING
구문을 빌드할 수 있습니다. 사용법은 where
메소드와 비슷합니다.
1 | knex('salaries') |
JOIN
join
메소드를 이용해 INNER JOIN
구문을 빌드할 수 있습니다.
1 | knex('employees') |
이 밖에 조인과 관련된 여러 메소드를 지원합니다.
leftOuterJoin
rightOuterJoin
fullOuterJoin
자세한 사용법은 공식 문서를 참고해주세요.
서브쿼리
단일 행 서브쿼리, 다중 행 서브쿼리 모두 자연스러운 방식으로 사용할 수 있습니다. Knex 인스턴스를 통해 작성한 쿼리 객체를, where
혹은 whereIn
메소드의 인자로 사용할 수 있습니다.
1 | // 1999년도 이전의 최고연봉보다 더 많은 연봉을 받은 사람들의 사원 번호를 출력합니다. |
1 | // first_name = 'Georgi' 를 만족하는 사람들의 last_name을 출력합니다. |
Utility Functions
.first()
Knex를 통해 쿼리를 실행하면 보통 배열이 반환됩니다. 이것은 limit(1)
처럼 하나의 행이 반환될 것이 확실한 경우에도 마찬가지입니다.
1 | knex('employees') |
매 번 하나의 행이 들어있는 배열을 다루는 것은 불편하므로, 아래와 같이 Knex 인스턴스의 first 메소드를 이용해서 배열이 아닌 객체가 반환되도록 동작을 바꿀 수 있습니다.
1 | knex('employees') |
만약 반환된 행이 없다면 first의
결과는 undefined가
됩니다.
.raw()
MySQL과 같은 DBMS에는 기능이 굉장히 많고, 또 버전이 올라가면서 추가되는 기능들도 많습니다. Knex에는 많은 기능들이 내장되어 있지만, DBMS의 모든 기능을 지원하는 것은 아닙니다. Knex가 지원하지 않는 기능(내장함수 등)을 Knex를 통해 사용하기 위해서는 직접 쿼리를 작성하는 작업이 필요한데, 이를 위해 Knex는 아래와 같은 메소드들을 가지고 있습니다.
raw
whereRaw
joinRaw
havingRaw
groupByRaw
orderByRaw
이 중 raw
메소드를 이용하면 직접 작성한 쿼리를 여러 메소드에서 사용할 수 있습니다. 아래의 예제를 참고해주세요.
1 | knex('users') |
주의!
위 예제와 같이 raw
관련 메소드들 특별한 방식으로 쿼리에 변수를 삽입하게 만들어져 있습니다. 쿼리 내에 변수를 삽입하고 싶은 경우에는 반드시 raw
메소드가 제공하는 방법을 통해서 해야 합니다.
예를 들어, 위 예제의 orWhere
안에 있는 raw
메소드를 아래와 같이 작성할 수도 있을 것입니다.
knex.raw(‘status <> ?’, [1]) 1부분에 원하는 변수를 꼭 넣어야한다! 안의 값으로는 req.body, req.params 등과 같은 값들을 넣을 수 있다.
1 | // 주의! |
위와 같이 작성된 코드는 SQL injection
공격에 무방비로 노출되게 됩니다. 따라서, 쿼리 문자열 내에 변수를 삽입할 때는 절대로 ES2015의 template literal을 사용하지 마시고
, raw
메소드가 제공하는 방식을 사용하세요.
raw
메소드의 자세한 사용법은 공식 문서를 참고해주세요.