관련글 : [Typescript Express] Sequelize로 MySQL 연결하기
[01 model 생성하기 ]
- MongoDB와의 차이점은 일단 schema 폴더를 사용하지 않고 model을 정의하는 파일에서 생성도 같이하는게 더 편하다는 것이었다.
- 그런데 이제 이게... 진짜 처음에 감도 못잡아서 많이 헤멘 부분인데 이 블로그와 공식문서가 정말 도움이 되었다
(1) user.ts 파일
- 지금 구현하는 User 모델의 ERD 설계는 다음과 같다. model/user.ts 파일에 작성한다.
- 먼저 sequelize에서 DataTypes와 Model을 import하고 만들어 둔 sequelize 연결 정보를 불러온다.
- 그리고 Users 모델에 들어갈 컬럼들을 형식에 맞게, nullable을 확인하고 interface로 정의한다.
- 생성한 interface에 맞는 Model 객체를 상속하는 Users 클래스를 만든다.
import { DataTypes, Model } from "sequelize";
import sequelize from "./index";
// These are all the attributes in the User model
interface UsersAttributes {
pk_user_id: string;
user_name: string;
email: string;
password: string;
gender?: string;
age_range?: string;
job?: string;
}
export class Users extends Model<UsersAttributes> {
pk_user_id: string;
user_name: string;
email: string;
password: string;
gender?: string;
age_range?: string;
job?: string;
}
- 윗 부분은 TypeScript에서 접근할 모델을 정의한 느낌이라면 그 아래는 실제 DB에 들어갈 타입과 옵션을 정해 모델을 생성해준다.
- 처음에 init과 define의 차이가 헷갈렸는데 결국 똑같은 기능을 한다고 한다. (define이 init을 호출하는 구조)
Users.init(
{
pk_user_id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
user_name: {
type: DataTypes.STRING(20),
allowNull: false,
},
email: {
type: DataTypes.STRING(20),
allowNull: false,
unique: true,
},
password: {
type: DataTypes.STRING(70),
allowNull: false, // Oauth 로그인은 비번 필요없으니 Nullable하게 하기도 함
},
gender: {
type: DataTypes.ENUM("F", "M"),
allowNull: true,
},
age_range: {
type: DataTypes.STRING(10),
allowNull: true,
},
job: {
type: DataTypes.STRING(20),
allowNull: true,
},
},
{
sequelize, // 꼭 넣어줘야 함
modelName: "Users",
tableName: "tb_user",
freezeTableName: true, // 테이블명 변경 불가
timestamps: true, // create_at, updated_at 컬럼 생성
paranoid: true, // deleted_at 컬럼 생성, soft delete 시 나중에 복구 가능
underscored: true, // 위 세 가지 타임스탬프의 컬럼명 표기법 설정, true로 하면 snake case / false면 camel case
},
);
- 주의할 점은 unique = true 옵션을 잘못 설정했다가는 SequelizeUniqueConstraintError 가 날 수 있으므로 조심한다.
- (당연한 말이지만) 위의 email처럼 테이블 전체에서 고유한 값일 경우에만 설정한다.
- 1:n, n:m 관계에서는 설정에 신중하거나 아래의 indexes unique = true로 여러 fields를 사용하자.
- 그리고 Users 모델에서는 따로 설정하지 않았지만 추가로 indexes 옵션이 있다.
💡 여기서 잠깐, 인덱스란? 💡
- 인덱스 설정은 insert, update, delete의 성능을 희생하고 대신 select의 성능을 향상시킨다.
- 따라서 인덱스가 없는 컬럼을 조건으로 update, delete를 하게 되면 굉장히 느려 많은 양의 데이터를 삭제해야 하는 상황에선 인덱스로 지정된 컬럼을 기준으로 진행하는 것이 빠르다.
- 또한 인덱스를 설정할 때는 중복도가 낮은(카디널리티가 높은) 컬럼을 선택하는 것이 좋다.
- 마지막으로 여러 컬럼으로 인덱스를 설정했을 시 field에서 첫 번째 컬럼이 포함돼야 인덱스를 타고 쿼리를 조회한다.
- 이 블로그에 엄청 자세하게 나와있어서 읽어보면 도움이 될 것이다.
- 기본적으로 Sequelize를 사용해서 테이블을 생성하면 primary key, foreign key 혹은 unique = true 설정이 되어 있는 컬럼에 대해서는 indexes가 자동으로 설정되었다.
- 이외의 컬럼 중 자주 조회하거나 자주 같이 조회하는 조합이 있다면, 다음과 같이 indexes 옵션을 사용해서 인덱스 설정을 추가한다.
- name은 인덱스 이름, field는 인덱스를 걸 컬럼들을 의미하고, 여기에는 없지만 unique key로 사용하고 싶다면 unique = true 옵션을 줄 수 있다.
{
sequelize,
modelName: "Schedules",
tableName: "tb_schedule",
freezeTableName: true,
timestamps: true,
paranoid: true,
underscored: true,
indexes: [
{ name: "IDX_type", using: "BTREE", fields: ["type"] },
{ name: "IDX_start_finish", using: "BTREE", fields: ["start", "finish"] },
],
},
(2) 1.create-table-user.ts 파일
- 정의한 모델을 테이블로 만들기 위해서는 migration 이라는 작업을 거쳐 DB와 sync를 맞춰주어야 한다.
- 따라서 db/migrations/1.create-table-user.ts 와 같이 파일을 생성하고 다음 코드를 넣어준다.
- 이 때 처음 테이블을 생성하는 경우라면 상관 없지만 데이터가 쌓이고 나서 테이블 설정을 변경하는 경우에 기존의 table을 Drop하고 새롭게 만들고 싶다면 sync( ) 안에 force: true 옵션을 넣어주고, 그렇지 않다면 반드시 빼줘야 한다.
import { Users } from "../models/user";
console.log("======Create user Table======");
const create_table_user = async () => {
// model 설정 변경만 반영하고 싶을 때
await Users.sync()
// 기존 테이블 Drop 후 새롭게 만들 때
// await Users.sync({ force: true })
.then(() => {
console.log("✅Success Create user Table");
})
.catch((err: Error) => {
console.log("❗️Error in Create user Table : ", err);
});
};
create_table_user();
- 그리고 powershell이나 cmd 등의 터미널 창에서 다음 명령어를 실행해준다.
./node_modules/.bin/ts-node .\src\db\migrations\1.create-table-user.ts
- 이 때 명령어가 실행되지 않는다면 VSC를 관리자 권한으로 실행하고 터미널에 다음 명령어를 순서대로 입력하고 다시 시도한다. (참고)
Get-ExecutionPolicy
Set-ExecutionPolicy RemoteSigned
- 정상적으로 실행되었다면 Workbench, MySQL-CLI 등에서 확인해볼 수 있다.
'엘리스 AI트랙 4기 > 프로젝트' 카테고리의 다른 글
[TypeScript Express] Sequelize 외래키로 참조 테이블 데이터 검색하기 (0) | 2022.06.16 |
---|---|
[TypeScript Express] Sequelize로 MySQL 모델 Association 관계 설정하기 (0) | 2022.06.15 |
[TypeScript Express] 라우터, 컨트롤러, 미들웨어 분리 (0) | 2022.06.10 |
[Typescript Express] 로그인 로직에 JWT Token Middleware 적용하기 (0) | 2022.06.09 |
[Typescript Express] Sequelize로 MySQL 연결하기 (0) | 2022.06.08 |