안녕하세요.
Hynn 입니다.
이번 포스팅에서는 NodeJS 환경에서 실제 Sequelize 를 사용해서, 어떻게 구현하는지를 예제 형태로의 코드를 작성해보도록 하겠습니다.
가장 간단한 환경에서 게시판을 구현하는 방식으로 진행하였으며, 코드의 대한 해설과 함께 진행해보도록 하겠습니다.
아래의 순서대로 작성이 진행됩니다.
=============
1. Sequelize Class Template 함수
=============
1. Sequelize Class Template 함수
Sequelize 는 이전 포스팅에서 설치에 대한 것은 다루어 본 적이 있습니다.
이제 실제 Sequelize 를 이용해서 기초적으로 DB를 구성하는 틀을 작성해보려고 합니다.
여기서는 "Class" 를 이용해 간편하게 테스트를 할 수 있는 환경 위주로 작성을 할 예정입니다.
1) Sequelize 설정을 위한 Config 구성
const config = {
db : {
development : {
username : 'Hynn',
password : 'hyunsign.tistory.com',
database : 'HynnBlog',
port : '3306',
host : "127.0.0.1",
dialect : 'mysql',
define : {
freezeTableName : true,
timestamps : false
}
}
}
};
module.exports = config;
위와 같이 설정을 기초적으로 구성해야 합니다.
물론.env 와 같은 형태의 파일로 이러한 변수를 별도로 담아 둘 수는 있겠지만, 예제 코드를 작성하기 위해 위와 같이 설정을 먼저 하도록 하겠습니다.
여기서 다시한번 짚고 가야할 부분은 3가지가 되겠습니다.
Dialect : Sequelize 에서 사용할 DataBase 유형을 지정해야 합니다.
Define - FreezeTableName : 테이블 이름을 고정으로 설정합니다.
Define - timestamps : Table Field 에서 Timestamp 를 비활성화 하는 설정입니다.
위 사진을 예제로 참고하시면, TimeStamp 의 true,false 에 따른 TableField 의 변화를 살펴볼 수 있습니다.
이후에 활용이 된다면 유용하게 활용할 수도 있는 기능이기도 합니다.
이제 이를 설정했다면, "Models" 이라는 Directory 를 생성하고, 이곳에 각 Table 별 구성요소를 생성하도록 하겠습니다.
const Sequelize = require('sequelize');
const { db } = require("../config");
const env = process.env.NODE_ENV || "development";
const config = db[env];
const sequelize = new Sequelize(config.database, config.username, config.password, config);
;(async () => {
await sequelize.sync ({force : true})
});
module.exports = {
Sequelize,
sequelize,
};
먼저 Sequelize Module 을 변수에 담아와야 합니다. 그리고 new 생성자를 사용해서 소문자와 대문자로 구분했습니다.
이 두개의 차이는 잘 사용을 해야하므로, 꼭 기억해두어야 합니다.
그리고 async 를 사용한 즉시함수를 설정하여, sync, 생성의 함수를 작성하고 {} 내에 Force를 설정해서, 함수가 실행될 때마다, DB Table 을 덮어쓰기 형태로 설정합니다.
이렇게 설정하면, 매번 테이블이 초기화되기때문에, 부담없이 테스트가 가능합니다.
이를 이용해서 다양한 함수를 테스트할 수 있습니다.
2. 기본 동작 구문
module.exports = (sequelize, Sequelize) => {
class User extends Sequelize.Model {
static initialize() {
return super.init({
userId :{
type: Sequelize.STRING(60),
primaryKey : true,
},
userPw : {
type: Sequelize.STRING(64),
allowNull : false,
},
username :{
type:Sequelize.STRING(32),
allowNull : false,
},
provider :{
type: Sequelize.ENUM("local", "kakao"),
allowNull : false,
defaultValue : "local",
},
snsId:{
type:Sequelize.STRING(128),
allowNull : true,
},
},
{
sequelize,
}
)
}
static associate(models){
super.hasMany(models.Board, {
foreignKey : "userId",
})
super.hasMany(models.Comment, {
foreignKey : "userId",
})
super.belongsToMany(models.Board, {
through : "Liked",
foreignKey : "userId"
})
}
}
User.initialize()
}
위의 함수에서는 "Module.exports" 를 사용해서 그 내부에 "Class" 를 담아 바로 내보내기 형태로 작성이 되었습니다.
여기서 Sequelize 를 정의하는 "Define" 을 사용하는 대신 "init", "initialize" 를 사용하여 구성했습니다.
Class 명은 Table Name 으로 지정이 되고, Extended 에 들어가는 부모 요소로 지정되는 "Sequelize.model" 은 index 에서 사용된 new Sequelize 의 Model 객체를 가르킵니다.
각각의 속성을 Console.log 로 출력하면서 확인한다면 보다 이해가 쉬울 것으로 생각됩니다.
그리고 각각의 Field 의 ForeignKey 설정을 부여하면 Class 생성의 기초가 작성됩니다.
다른 테이블의 작성 역시 기본적인 작성은 같으므로 생략하겠습니다.
이제 이를 더미 데이터 형태로 삽입하여 생성까지만 같이 시도해보도록 하겠습니다.
const Sequelize = require('sequelize');
const { db } = require("../config");
const env = process.env.NODE_ENV || "development";
const config = db[env];
const fs = require("fs");
const path = require('path');
const sequelize = new Sequelize(config.database, config.username, config.password, config);
const dir = fs.readdirSync(__dirname)
.filter((v)=> v.indexOf('model') !== -1)
.forEach((filename)=>{
require(path.join(__dirname, filename))(sequelize,Sequelize)
})
const {models} = sequelize
for (const key in models){
models[key].associate(models)
};
;(async () => {
await sequelize.sync ({ force : true,});
const { User, Board, Comment , Hash } = models;
await User.create({userId : 'choihwoong1', userPw :'1234', username : 'Admin'});
await User.create({userId : 'choihwoong2', userPw :'1234', username : 'Admin'});
await User.create({userId : 'choihwoong3', userPw :'1234', username : 'Admin'});
await User.create({userId : 'choihwoong4', userPw :'1234', username : 'Admin'});
await User.create({userId : 'choihwoong5', userPw :'1234', username : 'Admin'});
await User.create({userId : 'choihwoong6', userPw :'1234', username : 'Hynn'});
await Board.create({ subject : "안녕하세요", content : "1234" , userId : "choihwoong1"});
await Board.create({ subject : "안녕하세요", content : "1234" , userId : "choihwoong2"});
await Board.create({ subject : "안녕하세요", content : "1234" , userId : "choihwoong3"});
await Board.create({ subject : "안녕하세요", content : "1234" , userId : "choihwoong4"});
await Board.create({ subject : "안녕하세요", content : "1234" , userId : "choihwoong5"});
await Board.create({ subject : "안녕하세요", content : "1234" , userId : "choihwoong6"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong6" ,boardId : "1"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong6" ,boardId : "1"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong6" ,boardId : "2"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong5" ,boardId : "2"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong4" ,boardId : "3"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong3" ,boardId : "3"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong4" ,boardId : "4"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong3" ,boardId : "4"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong2" ,boardId : "5"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong2" ,boardId : "5"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong1" ,boardId : "6"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong1" ,boardId : "6"});
await Comment.create({ content : "테스트입니당" , userId : "choihwoong1" ,boardId : "6"});
const body = {
subject : "새로운 글 등록",
content : "테스트 오우버",
Hashtag : ["#javascript", "#hello", "#world", "#Hynn", "#Tistory"]
};
const cookies = {
userId : 'choihwoong1'
};
const req = {body, cookies};
const {Hashtag, ...rest} = req.body;
const board = await Board.create(rest);
const Hashtags = Hashtag.map((tag)=> Hash.findOrCreate({where : {tag }}));
const tags = await Promise.all(Hashtags);
await board.addHashes(tags.map((v)=>v[0]));
const Id = 7
const view = await Board.findOne({
where : {id : Id},
include : {
model : User,
attributes : ["username"],
}
})
const Comments = await view.getComments()
const HashT = (await view.getHashes({raw : true})).map(v=>({tag:v.tag}));
console.log("comments", Comments)
console.log('hashs', HashT)
})();
module.exports = {
Sequelize,
sequelize,
}
긴것처럼 보일수도 있으나, 실제 추가된 항목은 많지 않습니다.
즉시함수 내에서 먼저 DB에 추가될 항목을 수동으로 담아주었습니다. 위의 Sample 데이터를 이용해서 User,Board,Comment , Hash 의 인스턴트를 생성합니다.
기존같다면 req.body , cookie, 등에 있는 데이터를 Query 구문을 이용해 담겠지만, 위와 같이 샘플 데이터를 사용하였으므로, 이를 각각 개별적으로 지정하고, 이를 이용해 Sequelize method 를 사용해 Query 를 대체하였습니다.
여기서 가장 중요한것은 각각의 변수, 각각의 객체들의 Console 이 어떻게 구성되었는지를 한단계씩 밟아나가면서 탐색하는 것이 필요합니다.
가령 예를 들면 아래와 같습니다.
아래의 Console.log 는 위의 Sample code 에서 "console.log(board.__proto__) 라는 것을 출력하면 나타나는 method 입니다.
이 각각의 Method 는 단어 그대로 쉽게 확인할 수 있고, 이를 이용해서 작성자는 적절한 method 를 활용해야 합니다.
이것이 ORM 에서 기존의 query 구문이 아니라, 객체중심의 작성으로 이루어지는 이유이기도 합니다.
코드 해설에 대해서는 필요하시다면 문의주시면 제가 아는 선에서 성실하게 답변 드리도록 하겠습니다.
감사합니다.
'개발공부일지 > NodeJS' 카테고리의 다른 글
NodeJS - JWT Login Back-end Example (0) | 2023.01.19 |
---|---|
NodeJS - JWT (JSON Web Token) 기초 및 개념 이해하기 (0) | 2023.01.17 |
NodeJS - .ENV 를 이용해 환경변수 관리하기 (DOTENV) (0) | 2023.01.10 |
NodeJS - Ajax실제 작성예시 따라해보기 (0) | 2023.01.08 |
Node.JS - CORS 에 대하여 (0) | 2023.01.04 |
댓글