728x90
ORM
- Object Relational Mapping
- 객체지향 패러다임을 활용하여 관계형 데이터베이스(RDB)의 데이터를 조작하게 하는 기술이다.
- 직접 sql문을 작성하지 않아도 프로그래밍 언어를 이용해서 DB에 접속할 수 있다.
Sequelize
- ORM의 일종으로, 자바스크립트 객체와 데이터베이스의 릴레이션을 매핑해주는 도구이다.
- 프로그래밍 언어를 사용하여 DB에 접근할 수 있으므로 SQL 문법을 몰라도 된다는 장점을 가진다.
sequelize로 게시판 생성
#. 폴더의 경로는 다음과 같다.
1. app.js_웹 서버를 열기 위한 기본 세팅 설정
- 사용할 모듈을 저장 및 불러온다.
// npm i express ejs dotenv mysql2 sequelize
const express = require("express");
const path = require("path");
- 서버객체를 생성 하고 서버를 대기시킨다.
const app = express();
app.listen(6767,()=>{
console.log("서버열림");
})
- view 엔진의 경로를 설정하고 ejs를 사용한다.
app.set("views", path.join(__dirname,"page"));
app.set("view engine", "ejs");
- body객체를 사용한다.
app.use(express.urlencoded({extended:false}));
2. app.js_sequelize 구성 연결 매핑 설정
- ' /models/index.js '에서 db의 객체를 sequelize 모델로 매핑하여 등록한다.
- db의 객체로는 sequelize 모델로 정의한 객체들이 담겨있다.
- Sequelize.sync: 데이터베이스와 동기화 시켜주는 메소드이다.
// focus - true: 초기화
// focus - false: 초기화 안함
Sequelize.sync({focus : true}).then(()=>{
// 연결성공
}).catch((err)=>{
// 연결실패
console.log(err);
})
3. .env_sequelize 객체 생성 시 들어갈 데이터의 value값 설정한다.
- ' .env '에서 USERNAME을 사용하면 로컬 환경에서의 username을 가져오기 때문에 해당 이름은 사용할 수 없다.
USERNAMES = root
PASSWORD = 00000
DATABASE = test9
HOST = 127.0.0.1
4. config.js_sequelize 객체 생성 시 들어갈 데이터를 설정한다.
const dot = require('dotenv').config();
const config = {
dev: {
username: process.env.USERNAMES,
password: process.env.PASSWORD,
database: process.env.DATABASE,
host: process.env.HOST,
// dialect: 사용하는 데이터 베이스
dialect: "mysql"
}
}
module.exports = config;
4. posts.js_sequelize의 Post의 모델을 설정한다.
- Model클래스를 확장하면 정적 메소드 ' init( ) '을 사용할 수 있다.
- static init( )
- 테이블에 대한 설정을 한다.
- super.init( )을 통해 관련 인스턴스를 생성할 수 있다.
- super init( ){ { 컬럼의 내용 }, {테이블의 내용 } }
- 컬럼의 내용: 테이블의 컬럼이름과 속성 값을 전달한다.
- 테이블의 내용: 테이블 생성에 필요한 기타 값을 전달한다.
- super init( ){ { 컬럼의 내용 }, {테이블의 내용 } }
- static associate()
- 다른 모델과의 관계 (예. 1 : 1 / 1 : N)를 설정한다.
- 1 : N : 예) 하나의 유저가 여러 개의 글을 쓰는 경우
- 관계에 관한 메소드 (아래에 자세히 설명예정이다.)
- hasMany / belongsTo ( 1 : N )
- hasOne / belongsTo ( 1 : 1 )
- belongsToMany ( N : M)
- 다른 모델과의 관계 (예. 1 : 1 / 1 : N)를 설정한다.
- static init( )
- ⭐sequelize는 알아서 id 컬럼을 기본키로 연결하므로 별도로 설정해 줄 필요가 없다.
시퀄라이즈 옵션
- super.init의 두 번째 인수인 테이블에 대한 옵션
- sequelize
- static init 메서드의 매개변수와 연결되는 옵션으로,db.sequelize 객체를 넣어야 한다.
나중에 models/index.js에서 연결한다.
- static init 메서드의 매개변수와 연결되는 옵션으로,db.sequelize 객체를 넣어야 한다.
- timestamps
- 이 속성 값이 true면 시퀄라이즈는 createdAt과 updatedAt 컬럼을 추가하며, 각각 로우가 생성될 때와 수정될 때의 시간이 자동으로 입력된다.
- underscored
- 시퀄라이즈는 기본적으로 테이블명과 컬럼명을 스네이크 표기법 (snake case) 으로 만든다. 이를 카멜 표기법 (camel case) 으로 바꾸는 옵션이다
- 예) updated_at을 updatedAt 으로
- 시퀄라이즈는 기본적으로 테이블명과 컬럼명을 스네이크 표기법 (snake case) 으로 만든다. 이를 카멜 표기법 (camel case) 으로 바꾸는 옵션이다
- modelName
- 모델 이름을 설정할 수 있다. 노드 프로젝트에서 사용한다.
- tableName
- 실제 데이터베이스의 테이블 이름.
- 기본적으로 모델 이름의 소문자 및 복수형으로 만든다.
- 예를 들어 모델 이름이 User 라면 테이블 이름은 users 이다.
- paranoid
- true로 설정하면 deletedAt이라는 컬럼이 생긴다.
- 로우를 삭제할 때 완전히 지우지 않고, deletedAt에 지운 시각이 기록된다.
- 로우를 조회하는 명령을 내렸을 경우 deletedAt의 값이 null인 로우를 조회한다.
- true로 사용하는 이유? 후에 로우를 복원하기 위해서다.
- 로우를 복원해야 할 상황이 생길 것 같다면 미리 true로 설정해두자.
- charset / collate
- 각각 utf8 과 utf8_general_ci 로 설정해야 한글이 입력된다.
이모티콘까지 입력할 수 있게 하고 싶다면 utf8mb4 와 utf8mb4_general_ci 를 입력한다.
- 각각 utf8 과 utf8_general_ci 로 설정해야 한글이 입력된다.
모델간의 관계
- 1:N 관계 (hasMany, belongsTo)
- hasMany
- 시퀄라이즈에서 1:N관계를 정의해준다.
- 다른 테이블의 칼럼의 내 테이블의 칼럼을 참조한다.
- 첫 번째 메소드: 연결을 할 테이블을 기입한다.
- 두 번째 메소드 : 참조를 정의해주는 객체를 정의한다.
- foreignkey
- 다른 테이블에서 내 칼럼을 참조할 새로운 칼럼의 이름을 기입한다.
- 따로 지정하지 않으면 " 모델명 + 기본키 "가 이름인 칼럼이 자동으로 생성된다.
- 모델명: user
- 기본키: id
- foreignkey 이름은 userid이다.
- sourceKey
- foreignkey로 참조할 내 테이블의 칼럼을 적어준다.
- foreignkey
- belongsTo
- 내 테이블의 칼럼은 다른 테이블의 칼럼에 속해있다.
- belongsTo
- foreignkey
- 내 테이블이 참조 받을 다른 칼럼의 이름을 기입한다.
- 따로 지정하지 않으면 " 모델명 + 기본키 "가 이름인 칼럼이 자동으로 생성된다.
- 모델명: user
- 기본키: id
- foreignkey 이름은 userid이다.
- targetKey
- foreignkey로 참조한 다른 테이블의 칼럼을 적어준다.
- foreignkey
- hasMany
- 1:1 관계 (hasOne, belongsTo)
- hasOne
- foreignkey, sourceKey, targetKey의 내용은 위와 같다.
- belongsTo
- 위에 기입한 내용과 같다.
- hasOne
- N:M 관계 (belongsToMany)
- 어느 한 테이블이 다른 테이블에 종속하는 것이 아닌, 서로의 데이터를 공유한다.
- N:M 관계의 특성 상 새로운 모델이 다음과 같이 생성되며 ' through ' 속성에 이름을 적으면 된다.
// N:M 관계 정의 예시 코드 -------------------------------------------------------------
// 출처 : https://inpa.tistory.com/
// Post
db.Post.belongsToMany(db.Hashtag, { through: 'PostHashtag' });
// Hashtag
db.Hashtag.belongsToMany(db.Post, { through: 'PostHashtag' });
//posts.js -------------------------------------------------------------------------
const Sequelize = require("sequelize");
class Post extends Sequelize.Model {
static init(sequelize){
// 첫 번째 매개변수: 컬럼의 내용 / 두 번째 매개변수: 테이블의 내용
return super.init({
msg: {
type : Sequelize.STRING(100),
allowNull : false
}
},{
sequelize,
timestamps: true,
modelNameL : "Post",
tableName: "posts",
charset : "utf8",
collate : "utf8_general_ci"
})
}
static associate(db){
// 1 : N 관계
// belongsTO 메소드를 사용해서 user에 id를 foreignkey로 연결한다.
// 유저의 id가 따라갈 키. 참조키는 user_id
db.Post.belongsTo(db.User, { foreignkey : "user_id", targetKey : "id"});
}
}
module.exports = Post;
4. users.js_sequelize의 User의 모델을 설정한다.
const Sequelize = require("sequelize");
// User클래스에 시퀄라이즈 안의 Model클래스를 상속 시켜준다.
class User extends Sequelize.Model {
static init(sequelize){
return super.init({
// name 컬럼
name : {
// VARCHAR === STRING
type: Sequelize.STRING(20),
// allowNull: null을 허용할지 여부를 결정
allowNull : false,
// unique: 고유키로 사용할 것인지. 중복되는 않는 값
unique : true,
// primaryKey: 고유키로 설정할 것인지 유무
// primaryKey : true
},
age : {
// INT === INTEGER
type : Sequelize.INTEGER,
allowNull : false
},
msg: {
// TEXT === TEXT
type : Sequelize.TEXT
}
},{
sequelize,
timestamps : true,
underscored: false,
modelName: "user",
tableName: "users",
paranoid : false,
// 인코딩 방식이다. 필수로 작성해줘야하는 것!
charset : "utf8",
// 인코딩 방식이다. 필수로 작성해줘야하는 것!
collate : "utf8_general_ci"
});
}
static associate(db){
// 1 : N 관계
db.User.hasMany(db.Post, { foreignkey : "user_id", sourceKey : "id"});
};
};
module.exports = User;
5. index.js_sequelize의 객체를 생성하고, db 객체를 내보내준다.
const Sequelize = require("sequelize");
const config = require("./config");
const User = require("./users");
const Post = require("./posts")
// 시퀄라이즈 객체 생성
const _sequelize = new Sequelize(
config.dev.database,
config.dev.username,
config.dev.password,
config.dev
);
// 내보내 줄 빈 객체
const db = {};
db.Sequelize = _sequelize;
db.User = User;
db.Post = Post;
// 테이블을 초기화 하는 구문
User.init(_sequelize);
Post.init(_sequelize);
User.associate(db);
Post.associate(db);
module.exports = db;
5. create.ejs_유저를 등록할 수 있는 페이지를 생성한다.
<body>
<form action="/create" method="post">
<input type="text" name="name" placeholder="이름"> <br>
<input type="text" name="age" placeholder="나이"> <br>
<input type="text" name="msg" placeholder="메세지"> <br>
<button>유저 등록</button>
</form>
</body>
6. view.ejs_특정 유저가 등록한 게시글들을 확인할 수 있는 페이지를 생성한다.
<body>
<div>작성자: <%= data.name %></div>
<ul>
<% data.Posts.forEach((el) => { %>
<li>
<p><%= el.id %></p>
<p><%= el.msg %></p>
</li>
<% }); %>
</ul>
</body>
7. main.ejs_등록한 유저 목록을 확인할 수 있고, 유저별로 게시글을 작성할 수 있는 페이지를 생성한다.
- 유저마다 부여된 ' 글 등록 '버튼을 반복문 forEach문으로 돌려 해당 버튼의 index값을 받아, input의 value 값과 유저이름에 적용된 ' id=name ' 값을 불러온다.
- 불러온 값을 ajax 메소드를 사용하여 data의 객체로 app.js에 전달해준다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<h1>유저 페이지</h1>
<ul>
<% data.forEach((el)=> { %>
<li>
<span class="name"><%= el.name %></span>님 (<%= el.age %>세)
<div>코멘트 : <%= el.msg %></div>
<input type="text" class="item-input"> <button class="item-btn">글 등록</button>
</li>
<% }); %>
</ul>
</body>
<script>
// ajax: 요청과 응답에 대한 처리를 할 수 있게 도와주는 메소드
window.onload = ()=>{
let btns = document.querySelectorAll('.item-btn');
btns.forEach((el, index)=>{
el.onclick = ()=>{
let value = document.querySelectorAll('.item-input')[index].value;
let name = document.querySelectorAll('.name')[index].innerText;
console.log("value", value);
console.log("name", name);
//요청해서 값을 넣자 form tag 사용 X
// ajax 메소드 사용
$.ajax({
//요청할 url
url : "/create_post",
// 요청 방식
type : "post",
// 전달할 데이터
data: { name, value }
})
}
})
}
</script>
</html>
8. app.js_ejs 파일별 router와 post를 정의해준다.
- create.ejs => ' / '경로 | ' /create ' 경로에서 받은 input의 값으로 User 컬럼에 데이터를 추가한다.
app.get('/',(req,res)=>{
res.render("create")
})
app.post('/create',(req,res)=>{
const { name, age, msg } = req.body;
// create메소드: insert 문을 실행시켜주는 메서드
// 매개변수로 컬럼의 내용을 객체로 만들어서 전달
User.create({
// name 컬럼의 값
name : name,
// age 컬럼의 값
age : age,
// msg 컬럼의 값
msg : msg
})
res.send("값 추가 완료")
})
- main.ejs => ' /main '경로. 'findAll' 메소드를 사용하여 모든 유저의 정보를 불러온다.
app.get('/main',(req,res)=>{
// 유저 전체 조회
// findAll메소드: 매개변수로 검색 조건을 객체로 추가할 수 있다.
// 지금은 전체조회를 할 것이기 때문에 조건을 넣지 않는다.
// SELECT * FROM User 한거랑 같구나
User.findAll({})
.then((e)=>{
// 성공 시
res.render("main", { data : e });
})
.catch((e)=>{
// 실패 시
res.send("유저 조회 실패")
})
})
- main.ejs => ' /create_post '경로(글 등록 버튼을 누르면 요청되는 url이다). | ' /create_post ' 경로에서 받은 값을 받아 User 테이블 영역에서 해당 유저가 존재하는지를 검색하고 있다면 input의 value 값으로 받은 내용을 Post 값으로 추가한다.
app.post('/create_post', (req,res)=>{
const { name, value } = req.body;
console.log("name, value",name, value);
// findOne: 한 개의 값을 조회하는 메소드
User.findOne({
// 검색 조건 추가
where : {name: name}
}).then((e)=>{
Post.create({
msg : value,
userId : e.id
})
})
res.send();
})
- view.ejs => ' /view/:name ' 경로. 'findOne'메소드를 사용해서 params의 값을 불러와 조건으로 넣어 유저정보를 검색한 후 검색된 유저의 정보의 id로 참조된 Post 테이블의 값을 불러온다.
- 불러와진 Post 값이 then 함수의 매개변수로 담겨, 우리가 원하는 정보를 사용하기 위해, 반환 받은 ' e.dataValues.post '의 dataValues를 map함수로 돌아 'e.dataValues.Posts '로 대입한다.
- 이 과정을 거치면 하단의 사진처럼 값이 불러와진다.
- 이렇게 반환받은 값을 view 페이지에 넘겨준다.
app.get('/view/:name',(req,res)=>{
// 유저를 조회하고 가지고 있는 글을 볼거임!
User.findOne({
where : {
// 해당 이름의 유저를 조회하면서
name : req.params.name
},
// raw 속성을 주면 관계형으로 불러온 값을 다 풀어서 볼 수가 있는데
// raw: true,
// 해당 유저의 id로 참조된 user_id가 있는 post 테이블의 값을 같이 조회한다.
include : [
// 조회할 모듈 = Post모델
{model : Post}
]
}).then((e)=>{
e.dataValues.Posts = e.dataValues.Posts.map((i)=> {return i.dataValues});
const Posts = e.dataValues;
res.render("view", {data : Posts});
})
})
728x90
'블록체인_9기 > 💚 Node.js' 카테고리의 다른 글
38강_230525_Node.js(socket을 이용하여 채팅방 만들기) (0) | 2023.06.02 |
---|---|
37강_230524_Node.js(web socket, socket.io) (0) | 2023.05.31 |
33강_230518_ Node.js(VScode extension으로 Mysql DB연결) (0) | 2023.05.22 |
32강_230516_Node.js(암호화, Hash 암호화, crypto, 해시화, salt, 키 스트레칭 기법, Bcrypt) (2) | 2023.05.19 |
31강_230515_Node.js(Refresh token, Access token, cookie-parser) (0) | 2023.05.17 |