์ง๊ธ๊น์ง๋ ๋ฐ์ดํฐ๋ฅผ ์๋ฒ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ์
์ฝ์(CMD)์์ MySQL์ด ์ค์น๋ ๊ฒฝ๋ก๋ก ์ด๋
Connection Name์ localhost ์ ๊ณ ๋น๋ฐ๋ฒํธ ์
๋ ฅ
์๊น ์ค์ ํ๋ ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํ์ฌ ์ ์
์ ์์ด ๋์๋ค๋ฉด ์ฑ๊ณต
์ฝ์์์ MySQL ํ๋กฌํํธ์ ์ ์
- CREATE SCHEMA nodejs;๋ก nodejs ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ฑ
- use nodejs;๋ก ์์ฑํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ํ
MySQL ํ๋กฌํํธ์์ ํ ์ด๋ธ ์์ฑ
- CREATE TABLE [๋ฐ์ดํฐ๋ฒ ์ด์ค๋ช .ํ ์ด๋ธ๋ช ]์ผ๋ก ํ ์ด๋ธ ์์ฑ
- ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ํ ์ด๋ธ
๋์ด, ๊ฒฐํผ ์ฌ๋ถ, ์ฑ๋ณ๊ฐ์ ์ ๋ณด๊ฐ ์ปฌ๋ผ
์ค์ ๋ก ๋ค์ด๊ฐ๋ ๋ฐ์ดํฐ๋ ๋ก์ฐ
id INT NOT NULL AUTO_INCREMENT
- ์ปฌ๋ผ๋ช ์์ ๊ฒ๋ค์ ์ปฌ๋ผ์ ๋ํ ์ต์ ๋ค
- INT: ์ ์ ์๋ฃํ(FLOAT, DOUBLE์ ์ค์)
- VARCHAR: ๋ฌธ์์ด ์๋ฃํ, ๊ฐ๋ณ ๊ธธ์ด(CHAR์ ๊ณ ์ ๊ธธ์ด)
- TEXT: ๊ธด ๋ฌธ์์ด์ TEXT๋ก ๋ณ๋ ์ ์ฅ
- DATETIME: ๋ ์ง ์๋ฃํ ์ ์ฅ
- TINYINT: -128์์ 127๊น์ง ์ ์ฅํ์ง๋ง ์ฌ๊ธฐ์๋ 1 ๋๋ 0๋ง ์ ์ฅํด ๋ถ ๊ฐ ํํ
- NOT NULL: ๋น ๊ฐ์ ๋ฐ์ง ์๋๋ค๋ ๋ป(NULL์ ๋น ๊ฐ ํ์ฉ)
- AUTO_INCREMENT: ์ซ์ ์๋ฃํ์ธ ๊ฒฝ์ฐ ๋ค์ ๋ก์ฐ๊ฐ ์ ์ฅ๋ ๋ ์๋์ผ๋ก 1 ์ฆ๊ฐ
- UNSIGNED: 0๊ณผ ์์๋ง ํ์ฉ
- ZEROFILL: ์ซ์์ ์๋ฆฌ ์๊ฐ ๊ณ ์ ๋ ๊ฒฝ์ฐ ๋น ์๋ฆฌ์ 0์ ๋ฃ์
- DEFAULT now(): ๋ ์ง ์ปฌ๋ผ์ ๊ธฐ๋ณธ๊ฐ์ ํ์ฌ ์๊ฐ์ผ๋ก
PRIMARY KEY(id)
- id๊ฐ ํ ์ด๋ธ์์ ๋ก์ฐ๋ฅผ ํน์ ํ ์ ์๊ฒ ํด์ฃผ๋ ๊ณ ์ ํ ๊ฐ์์ ์๋ฏธ
- ํ๋ฒ, ์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ๊ฐ์ ๊ฐ๋
UNIQUE INDEX name_UNIQUE (name ASC)- ํด๋น ์ปฌ๋ผ(name)์ด ๊ณ ์ ํด์ผ ํจ์ ๋ํ๋ด๋ ์ต์
- name_UNIQUE๋ ์ด ์ต์ ์ ์ด๋ฆ(์๋ฌด๊ฑฐ๋ ๋ค๋ฅธ ๊ฑธ๋ก ์ง์ด๋ ๋จ)
- ASC๋ ์ธ๋ฑ์ค๋ฅผ ์ค๋ฆ์ฐจ์์ผ๋ก ์ ์ฅํจ์ ์๋ฏธ(๋ด๋ฆผ์ฐจ์์ DESC)![]
COMMENT: ํ ์ด๋ธ์ ๋ํ ๋ณด์ถฉ ์ค๋ช (ํ์ ์๋)
DEFAULT CHARSET: utf8๋ก ์ค์ ํด์ผ ํ๊ธ์ด ์ ๋ ฅ๋จ(utf8mb4 ํ๋ฉด ์ด๋ชจํฐ์ฝ ๊ฐ๋ฅ)
ENGINE: InnoDB ์ฌ์ฉ(์ด์ธ์ MyISAM์ด ์์, ์์ง๋ณ๋ก ๊ธฐ๋ฅ ์ฐจ์ด ์กด์ฌ)
DESC ํ ์ด๋ธ๋ช
ํ ์ด๋ธ ์ญ์ ํ๊ธฐ: DROP TABLE ํ ์ด๋ธ๋ช
comments ํ ์ด๋ธ ์์ฑ
๋๊ธ ํ ์ด๋ธ์ ์ฌ์ฉ์ ํ ์ด๋ธ๊ณผ ๊ด๊ณ๊ฐ ์์(์ฌ์ฉ์๊ฐ ๋๊ธ์ ๋ฌ๊ธฐ ๋๋ฌธ)
์ธ๋ํค๋ฅผ ๋์ด ๋ ํ ์ด๋ธ์ด ๊ด๊ณ๊ฐ ์๋ค๋ ๊ฒ์ ํ์
FOREIGN KEY (์ปฌ๋ผ๋ช ) REFERENCES ๋ฐ์ดํฐ๋ฒ ์ด์ค.ํ ์ด๋ธ๋ช (์ปฌ๋ผ)
FOREIGN KEY (commenter) REFERENCES nodejs.users (id)
๋๊ธ ํ ์ด๋ธ์๋ commenter ์ปฌ๋ผ์ด ์๊ธฐ๊ณ ์ฌ์ฉ์ ํ ์ด๋ธ์ id๊ฐ์ด ์ ์ฅ๋จ
ON DELETE CASCADE, ON UPDATE CASCADE
์ฌ์ฉ์ ํ ์ด๋ธ์ ๋ก์ฐ๊ฐ ์ง์์ง๊ณ ์์ ๋ ๋ ๋๊ธ ํ ์ด๋ธ์ ์ฐ๊ด๋ ๋ก์ฐ๋ค๋ ๊ฐ์ด ์ง์์ง๊ณ ์์ ๋จ
๋ฐ์ดํฐ๋ฅผ ์ผ์น์ํค๊ธฐ ์ํด ์ฌ์ฉํ๋ ์ต์ (CASCADE ๋์ SET NULL๊ณผ NO ACTION๋ ์์)
SHOW TABLES
Create, Read, Update, Delete์ ๋๋ฌธ์์ด
INSERT INTO ํ ์ด๋ธ (์ปฌ๋ผ๋ช ๋ค) VALUES (๊ฐ๋ค)
SELECT ์ปฌ๋ผ FROM ํ ์ด๋ธ๋ช
SELECT * ์ ๋ชจ๋ ์ปฌ๋ผ์ ์ ํํ๋ค๋ ์๋ฏธ
WHERE๋ก ์กฐ๊ฑด์ ์ฃผ์ด ์ ํ ๊ฐ๋ฅ
- AND๋ก ์ฌ๋ฌ๊ฐ์ง ์กฐ๊ฑด์ ๋์์ ๋ง์กฑํ๋ ๊ฒ์ ์ฐพ์
- OR๋ก ์ฌ๋ฌ๊ฐ์ง ์กฐ๊ฑด ์ค ํ๋ ์ด์์ ๋ง์กฑํ๋ ๊ฒ์ ์ฐพ์
ORDER BY๋ก ํน์ ์ปฌ๋ผ ๊ฐ ์์๋๋ก ์ ๋ ฌ ๊ฐ๋ฅ
- DESC๋ ๋ด๋ฆผ์ฐจ์, ASC ์ค๋ฆ์ฐจ์
LIMIT์ผ๋ก ์กฐํํ ๊ฐ์ ์ ํ
OFFSET์ผ๋ก ์์ ๋ก์ฐ๋ค ์คํต ๊ฐ๋ฅ(OFFSET 2๋ฉด ์ธ ๋ฒ์งธ ๊ฒ๋ถํฐ ์ฐพ์)
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์๋ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ ์์
- UPDATE ํ ์ด๋ธ๋ช SET ์ปฌ๋ผ=์๊ฐ WHERE ์กฐ๊ฑด
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์๋ ๋ฐ์ดํฐ๋ฅผ ์ญ์ ํ๋ ์์
- DELETE FROM ํ ์ด๋ธ๋ช WHERE ์กฐ๊ฑด
SQL ์์ ์ ์ฝ๊ฒ ํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
๐์ฐธ๊ณ
https://github.com/ZeroCho/nodejs-book/tree/master/ch6/6.5.2/learn-express
{
"name": "npmtest",
"version": "1.0.0",
"description": "์ ๋ฅผ ์ฝ์ด์ฃผ์ธ์.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "seokahi",
"license": "MIT"
}
์ํ๋ผ์ด์ฆ ๋ช ๋ น์ด ์ฌ์ฉํ๊ธฐ ์ํด sequelize-cli ์ค์น
๋ค์๊ณผ ๊ฐ์ด ์์
require(../config/config) ์ค์ ๋ก๋ฉ
new Sequelize(์ต์
๋คโฆ)๋ก DB์ ์ฐ๊ฒฐ ๊ฐ๋ฅ
๐ปmodels/index.js
const Sequelize = require('sequelize');
const User = require('./user');
const Comment = require('./comment');
const env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env];
const db = {};
const sequelize = new Sequelize(config.database, config.username, config.password, config);
db.sequelize = sequelize;
db.Sequelize = Sequelize;
db.User = User;
db.Comment = Comment;
User.init(sequelize);
Comment.init(sequelize);
User.associate(db);
Comment.associate(db);
module.exports = db;
app.js ์์ฑ
sequelize.sync๋ก ์ฐ๊ฒฐ
๐ปapp.js
const express = require('express');
const path = require('path');
const morgan = require('morgan');
const nunjucks = require('nunjucks');
const { sequelize } = require('./models');
const indexRouter = require('./routes');
const usersRouter = require('./routes/users');
const commentsRouter = require('./routes/comments');
const app = express();
app.set('port', process.env.PORT || 3001);
app.set('view engine', 'html');
nunjucks.configure('views', {
express: app,
watch: true,
});
sequelize.sync({ force: false })
.then(() => {
console.log('๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ฑ๊ณต');
})
.catch((err) => {
console.error(err);
});
app.use(morgan('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/comments', commentsRouter);
app.use((req, res, next) => {
const error = new Error(`${req.method} ${req.url} ๋ผ์ฐํฐ๊ฐ ์์ต๋๋ค.`);
error.status = 404;
next(error);
});
app.use((err, req, res, next) => {
res.locals.message = err.message;
res.locals.error = process.env.NODE_ENV !== 'production' ? err : {};
res.status(err.status || 500);
res.render('error');
});
app.listen(app.get('port'), () => {
console.log(app.get('port'), '๋ฒ ํฌํธ์์ ๋๊ธฐ ์ค');
});
DB ์ฐ๊ฒฐ ์ ๋ณด๋ฅผ ๋ฃ๊ธฐ
๐ปconfig/config.json
{
"development": {
"username": "root",
"password": "nodejsbook",
"database": "nodejs",
"host": "127.0.0.1",
"dialect": "mysql"
},
"test": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
}
}
npm start๋ก ์คํํด์ SELECT 1+1 AS RESULT๊ฐ ๋์ค๋ฉด ์ฐ๊ฒฐ ์ฑ๊ณต
ํ
์ด๋ธ์ ๋์๋๋ ์ํ๋ผ์ด์ฆ ๋ชจ๋ธ ์์ฑ
๐ปmodels/user.js
const Sequelize = require('sequelize');
module.exports = class User extends Sequelize.Model {
static init(sequelize) {
return super.init({
name: {
type: Sequelize.STRING(20),
allowNull: false,
unique: true,
},
age: {
type: Sequelize.INTEGER.UNSIGNED,
allowNull: false,
},
married: {
type: Sequelize.BOOLEAN,
allowNull: false,
},
comment: {
type: Sequelize.TEXT,
allowNull: true,
},
created_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
},
}, {
sequelize,
timestamps: false,
underscored: false,
modelName: 'User',
tableName: 'users',
paranoid: false,
charset: 'utf8',
collate: 'utf8_general_ci',
});
}
static associate(db) {
db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id' });
}
};
์ํ๋ผ์ด์ฆ ๋ชจ๋ธ์ ์๋ฃํ์ MySQL์ ์๋ฃํ๊ณผ ์กฐ๊ธ ๋ค๋ฆ
define ๋ฉ์๋์ ์ธ ๋ฒ์งธ ์ธ์๋ ํ
์ด๋ธ ์ต์
๐ปmodels.comment.js
const Sequelize = require('sequelize');
module.exports = class Comment extends Sequelize.Model {
static init(sequelize) {
return super.init({
comment: {
type: Sequelize.STRING(100),
allowNull: false,
},
created_at: {
type: Sequelize.DATE,
allowNull: true,
defaultValue: Sequelize.NOW,
},
}, {
sequelize,
timestamps: false,
modelName: 'Comment',
tableName: 'comments',
paranoid: false,
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci',
});
}
static associate(db) {
db.Comment.belongsTo(db.User, { foreignKey: 'commenter', targetKey: 'id' });
}
};
๐ปmodels/user.js
const Sequelize = require('sequelize');
module.exports = class User extends Sequelize.Model {
static init(sequelize) {
return super.init({
name: {
type: Sequelize.STRING(20),
allowNull: false,
unique: true,
},
age: {
type: Sequelize.INTEGER.UNSIGNED,
allowNull: false,
},
married: {
type: Sequelize.BOOLEAN,
allowNull: false,
},
comment: {
type: Sequelize.TEXT,
allowNull: true,
},
created_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
},
}, {
sequelize,
timestamps: false,
underscored: false,
modelName: 'User',
tableName: 'users',
paranoid: false,
charset: 'utf8',
collate: 'utf8_general_ci',
});
}
static associate(db) {
db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id' });
}
};
index.js์ ๋ชจ๋ธ ์ฐ๊ฒฐ
users ๋ชจ๋ธ๊ณผ comments ๋ชจ๋ธ ๊ฐ์ ๊ด๊ณ๋ฅผ ์ ์
1๋1 ๊ด๊ณ
๋ค๋๋ค ๊ด๊ณ
์ ์ค์ด SQL๋ฌธ, ์๋ซ ์ค์ ์ํ๋ผ์ด์ฆ ์ฟผ๋ฆฌ(์๋ฐ์คํฌ๋ฆฝํธ)
์ ์ค์ด SQL๋ฌธ, ์๋ซ ์ค์ ์ํ๋ผ์ด์ฆ ์ฟผ๋ฆฌ(์๋ฐ์คํฌ๋ฆฝํธ)
ํน์ํ ๊ธฐ๋ฅ๋ค์ธ ๊ฒฝ์ฐ Sequelize.Op์ ์ฐ์ฐ์ ์ฌ์ฉ(gt, or ๋ฑ)
1: true
์ ์ค์ด SQL๋ฌธ, ์๋ซ ์ค์ ์ํ๋ผ์ด์ฆ ์ฟผ๋ฆฌ(์๋ฐ์คํฌ๋ฆฝํธ)
์์
์ญ์
๊ฒฐ๊ณผ๊ฐ์ด ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด์
include๋ก JOIN ๊ณผ ๋น์ทํ ๊ธฐ๋ฅ ์ํ ๊ฐ๋ฅ(๊ด๊ณ ์๋ ๊ฒ ์ฎ์ ์ ์์)
๋ค๋๋ค ๋ชจ๋ธ์ ๋ค์๊ณผ ๊ฐ์ด ์ ๊ทผ ๊ฐ๋ฅ
get+๋ชจ๋ธ๋ช
์ผ๋ก ๊ด๊ณ ์๋ ๋ฐ์ดํฐ ๋ก๋ฉ ๊ฐ๋ฅ
as๋ก ๋ชจ๋ธ๋ช
๋ณ๊ฒฝ ๊ฐ๋ฅ
include๋ ๊ด๊ณ ์ฟผ๋ฆฌ ๋ฉ์๋์๋ where๋ attributes
๐์์ฑ ์ฟผ๋ฆฌ
์ฌ๋ฌ ๊ฐ๋ฅผ ์ถ๊ฐํ ๋๋ ๋ฐฐ์ด๋ก ์ถ๊ฐ ๊ฐ๋ฅ
์์ ์ set+๋ชจ๋ธ๋ช
, ์ญ์ ๋ remove+๋ชจ๋ธ๋ช
์ง์ SQL์ ์ธ ์ ์์
ํ๋ก ํธ ์ฝ๋๋ณด๋ค๋ ์๋ฒ ์ฝ๋ ์์ฃผ๋ก ๋ณด๊ธฐ
๐ปroutes/index.js
const express = require('express');
const User = require('../models/user');
const router = express.Router();
router.get('/', async (req, res, next) => {
try {
const users = await User.findAll();
res.render('sequelize', { users });
} catch (err) {
console.error(err);
next(err);
}
});
module.exports = router;
users ๋ผ์ฐํฐ
๐ปroutes/users.js
const express = require('express');
const User = require('../models/user');
const Comment = require('../models/comment');
const router = express.Router();
router.route('/')
.get(async (req, res, next) => {
try {
const users = await User.findAll();
res.json(users);
} catch (err) {
console.error(err);
next(err);
}
})
.post(async (req, res, next) => {
try {
const user = await User.create({
name: req.body.name,
age: req.body.age,
married: req.body.married,
});
console.log(user);
res.status(201).json(user);
} catch (err) {
console.error(err);
next(err);
}
});
router.get('/:id/comments', async (req, res, next) => {
try {
const comments = await Comment.findAll({
include: {
model: User,
where: { id: req.params.id },
},
});
console.log(comments);
res.json(comments);
} catch (err) {
console.error(err);
next(err);
}
});
module.exports = router;
comments ๋ผ์ฐํฐ
๐ปroutes/comment.js
const express = require('express');
const { Comment } = require('../models');
const router = express.Router();
router.post('/', async (req, res, next) => {
try {
const comment = await Comment.create({
commenter: req.body.id,
comment: req.body.comment,
});
console.log(comment);
res.status(201).json(comment);
} catch (err) {
console.error(err);
next(err);
}
});
router.route('/:id')
.patch(async (req, res, next) => {
try {
const result = await Comment.update({
comment: req.body.comment,
}, {
where: { id: req.params.id },
});
res.json(result);
} catch (err) {
console.error(err);
next(err);
}
})
.delete(async (req, res, next) => {
try {
const result = await Comment.destroy({ where: { id: req.params.id } });
res.json(result);
} catch (err) {
console.error(err);
next(err);
}
});
module.exports = router;
npm start๋ก ์๋ฒ ์์
๐์ถ์ฒ๐
Node.js ๊ต๊ณผ์ - ๊ธฐ๋ณธ๋ถํฐ ํ๋ก์ ํธ ์ค์ต๊น์ง
https://www.inflearn.com/course/%EB%85%B8%EB%93%9C-%EA%B5%90%EA%B3%BC%EC%84%9C/dashboard