Search
▪️

Understanding Sequelize

What is Sequelize?

Object-Relational Mapping(ORM) Library라고 하는 Third Party Package이다.
작성하여 넘긴 JSON을 화면 뒤에서 복잡한 SQL Code로 Mapping 시켜주는 것이 ORM이다.
따라서 JSON 형태의 데이터를 넘기면 자동으로 SQL 문을 실행시켜 주므로, 직접적으로 SQL 코드를 작성할 필요가 없다는 것이다.
Sequelize는 데이터베이스에 대해서 작업할 Model을 제공해주고, 이런 Model들을 Instantiate하게 해준다.
Model이 Instantiate 되었을 때, 이 Model에 대해서 Query를 수행시킬 수 있다. (Association도 가능하다.)

Connecting to the Database

Sequelize를 npm을 통하여 설치하려고 할 때, mysql2라는 Third Party Package가 설치되어 있어야 한다.
Sequelize Third Party Package를 설치했다면, 가장 먼저 해줘야 하는 것은 Sequelize를 이용하여 Model을 만들어야 한다는 것이다. (Model을 데이터베이스와 연결도 해주긴 해야 한다.)
Sequelize를 사용할 경우, 데이터베이스의 연결을 도왔던 helpers의 database.js에 Pool을 생성하는 코드를 사용하지 않고 Sequelize Instance를 생성하여 데이터베이스와 연결해준다. 아래와 같이 이용한다.
const Sequelize = require('sequelize') const sequelize = new Seqeulize($schemaName, $userName, $password, $mappingData)
Mapping Data에 dialect의 키 값으로, 사용하고 있는 데이터베이스 이름을 명시해준다. 이는 사용하는 데이터베이스의 Engine에 따라서 SQL Syntax가 달라질 수 있기 때문이다.
Mapping Data에 들어오는 또 다른 데이터인 host의 키 값으로는 접속할 데이터베이스의 위치를 명시한다.
위와 같이 작성하면 Sequelize Object를 생성하면서 동시에 자동으로 데이터베이스에 연결된다.
데이터베이스 연결 Pool의 필수적인 Sequelize Object를 Imort하여 사용할 수 있다.

Defining a Model

Sequelize를 이용하면, 기존에 파일 저장할 때나 SQL Code를 썼던 것과 같은 코드는 전혀 필요하지 않다.
Sequelize를 이용하여 Model을 정의하기 위해서, Sequelize Library를 Import해줘야 하고, Helper에 전역으로 선언한 Sequelize Instance가 필요하다.
Model은 Instance인 sequelize의 define() Method를 이용하여 정의한다. 이전에 작업했던 것처럼 Class형태를 띄지 않는다.
define()의 첫 번째 인자인 modelName은 전형적으로 소문자로 작성한다. 두 번째 인자인 Attributes들은 JSON형태로 작성하도록 한다.
Attributes들을 정의할 때, 어떤 인자를 주고 어떤 옵션을 줘야하는지 모르겠다면 Official Docs를 통해서 참고하여 작성하도록 한다.

Syncing JS Definition to the Database

정의한 Model을 이용하려면 Table이 있어야 하고, 이런 Table들은 Sequelize를 통해서 생성할 수 있다.
Table 생성은 Application이 실행할 때, Table 유무 확인 후 생성할 수 있도록 한다. (app.listen() 직전에 두는 것이 일반적이다.)
이 작업을 위해서 사용되는 Instance sequelize의 sync()라는 Method가 있다. 해당 Method는 정의된 모든 Model을 검토하고, 해당 Model에 대한 Table들을 자동으로 생성하게 한다. (이 때 Sync를 호출하는 Sequelize Instance와 Model을 생성한 Sequelize Instance는 같아야 한다.)
이를 실행시키면 Sequelize가 사용자를 대신해 Create Table에 대한 Query를 날린 것을 Query Log가 남은 것을 통해 확인할 수 있다.
Sequelize의 자동 Table 생성의 좋은 점은 createdAt, updatedAt, deletedAt과 같은 Timestamp를 관리해준다.

Inserting Data & Creating a Product

Model을 이용하여 데이터베이스에 데이터를 삽입하는 것은 create() / build() save() 이렇게 두 방법으로 나뉜다. create() Method는 Model에 기반하여 Element를 만들고 데이터베이스에 해당 Element를 즉시 저장한다. 반면, build() Method는 Model에 기반하여 Element를 만드는 것까지는 동일하지만 save() Method를 통해 수동으로 데이터베이스에 저장해야 한다.
create() Method에 들어오는 인자는 Mapping Data이며, Model에 정의된 대로 Attribute에 대한 값을 인자로 받는다.
Sequelize 역시 MySQL을 기반으로 하기 때문에 Promise 데이터로 작업하게 된다. 따라서 비동기 데이터 처리에 대해서 then(), catch()로 Chaining이 가능하다.

Retrieving Data & Fetching Products

기존에 File System을 이용하여 구현했던 fetchAll() Method 대신, Sequelize를 이용하면 findAll()을 통해서 쉽게 모든 데이터들을 불러올 수 있다. 해당 Method안에는 JSON 형태로 Option을 지정할 수 있다.
모든 데이터가 아니라 하나의 Matching되는 데이터를 받아오려면 findByPk() Method를 쓰면 된다. (혹은 findAll()을 통해 where Condition으로 조건을 줄 수도 있다.)

Updating Products

데이터베이스의 Record를 Update하기 위해서, Update할 항목을 먼저 찾은 뒤에 해당 항목의 Field 값들을 Locally 바꿔준다. Locally 바뀐 항목에 대해서 Instance인 sequelize의 save() Method를 통해 데이터베이스에도 바뀐 값들로 Update해준다. save() Method이용 시, 항목이 있다면 Update를 항목이 없다면 Create해준다.

Deleting Products

findById() Method나 findByPk() Method와 같이 deleteById() Method는 존재하지 않는다.
단, 삭제할 때는 destroy()라는 Method를 이용한다.
destroy()는 주어진 Option을 만족하는 모든 Records들을 삭제한다.
Option을 통해서 삭제를 해도 되지만, findByPk() Method를 찾은 뒤에 then()을 통해서 destory()를 호출하여도 무방하다.

Adding a One-To-Many & Many-To-Many Relationship

두 Model간의 Association에 대해서 Sequelize를 통해서 쉽게 정의할 수 있다.
x.belongsTo(y)라고 함은 y가 x를 생성했다로 볼 수 있다. belongsTo() Method의 두 번째 인자로는 두 Model의 관계에 대해서 어떻게 관리될 것인지를 명시한다. 이 때 constraints는 true, onDelete는 'CASCADE'로 두었다면, y가 삭제될 때 x도 같이 삭제된다.
belongsTo()와 같은 Method가 아닌, hasMany()라는 Method를 써도 된다. Inverse한 표현이며 두 관계는 x, y만 바뀌면 동일한 구문이다.
이렇게 두 Model에 대한 관계를 정의하고 난 뒤에, 이미 생성되어 있는 테이블 외에 새로운 테이블이 생성되지 않는 경우가 있을 수 있다. 이런 경우 기존에 있는 테이블에 대해서는 Override 시켜줘야 하는데 sync() Method에 {force: true}라는 인자를 주면 기존 Table을 Override하여 없는 Model에 대해서 새로운 Table 생성이 가능하다. (기존 Table도 Drop 후에 새로 Create되니 주의해야 한다.)
Model간의 관계 정의 시, 서로 참조할 수 있는 Foreign Key가 자동으로 생성된다.
정의된 관계에 대해서, Associated된 Model의 Foreign Key로 쓰이는 필드 값을 채우기 위해서 수동으로 Request에 담아서 데이터베이스에 넘겨줄 수도 있다. 하지만 더 마법 같은 방법으로, belongsTo() 혹은 hasMany()된 경우에 한에서 Associate Object를 생성하는 Method를 이용할 수 있다. (Magic Association이라 하고, 어떤 Model에 대해서 관계를 가진 Model을 Foreign Key에 맞춰서 생성해준다.)
이런 Magic Association의 경우 $model.create$singular(), $model.get$plural(), $model.add$singular 등이 있다. 단수, 복수 형태는 Sequelize가 알아서 판단한다.
belongsToMany() Method와 같이 Many-To-Many를 지향하는 경우, 중간 저장 Model이 필요하다. 이는 해당 함수의 두 번째 인자인 through의 키 값으로 준다.
Many-To-Many의 경우에도 Magic Association Method가 가능하다. 즉, through로 지정한 중간 저장 Model을 직접 이용하지 않더라도 Many-To-Many의 Model간 create, get이 모두 가능하다. 물론 add도 가능하다. 하지만 add를 사용할 경우 through로 주어진 중간 저장자를 이용해야 하고, 해당 인자를 별도로 주어야 한다.
만일 view에서 Many-To-Many Model을 이용하게 되었을 때, Dotting으로 중간 저장자의 요소를 접근할 수 있다.
Many-To-Many의 중간 저장자 항목을 삭제해야 명심해야 한다. 이 중간 저장자에 대해서도 Magic Association Method인 destroy() Method가 존재한다.
** then() Method에서 Return 되는 것들은 자동으로 new Promise로 Wrap해주기 때문이다. 따라서 별도로 Promise.resolve($return)을 해주지 않아도 된다.