์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- BOJ
- SwiftUI
- arkit
- UIKit
- Xcode
- BFS
- swift
- combine
- XCTest
- Lv2
- raywenderlich
- ๋ฐฑ์ค
- Swfit
- realm
- designpattern
- rxcocoa
- visionOS
- RxSwift
- ํจ์คํธ์บ ํผ์ค
- TCA
- tableView
- ํ๋ก๊ทธ๋๋จธ์ค
- reactorkit
- SnapKit
- CollectionView
- node.js
- MVVM
- Kuring
- Flutter
- ios
- Today
- Total
lgvv98
[Node.js] #7 MySQL ๋ณธ๋ฌธ
MySQL
๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณ์์ ์ ์ฅํ๋ค๋ ๊ฒ์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๋ค๋ ๊ฒ.
๋ฉ๋ชจ๋ฆฌ๋ ํ๋ฐ์ฑ์ด๋ผ ์ข ๋ฃํ๋ฉด ์ฌ๋ผ์ง.
์๊ตฌ์ ์ฅ์ ์ํด์๋ ๋ฐ๋ฒ ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
๋ค์ํ DB๊ฐ ์์ง๋ง MySQL๊ณผ ๋ชฝ๊ณ ๋๋น ๋๊ฐ์ง๋ฅผ ์ด์ฉํ ์์ .
# mysql ์ค์น
brew install mysql
brew services start mysql
mysql_secure_installation
# ์ํฌ๋ฒค์น ์ค์น
์ฝ์๋ก๋ ๋ฐ์ดํฐ๋ฅผ ํ๋์ ๋ณด๊ธฐ์ ๋ฌด๋ฆฌ๊ฐ ์์ผ๋ฏ๋ก ์ํฌ๋ฒค์น๋ผ๋ ํ๋ก๊ทธ๋จ์ ์ฌ์ฉํ๋ฉด ๋ฐ๋ฒ ๋ด๋ถ์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ์๊ฐ์ ์ผ๋ก ํ์ธํ ์ ์์ด์ ํธ๋ฆฌํจ.
# ํ ์ด๋ธ ์์ฑํ๊ธฐ
๋๋ถ๋ถ ์๋๊ฑฐ๋ผ ๋์ถฉ ๋๋ง ์์๋ณด๋๋ก ์ ๋ฆฌ
VARCHAR(์๋ฆฟ์): ๊ฐ๋ณ๊ธธ์ด
CHAR(์๋ฆฟ์): ๊ณ ์ ๊ธธ์ด
- ๋๋ค ์๋ฆฟ์๊ฐ 10์ด๋ผ๊ณ ํ๋ฉด, VARCHAR๋ 0~10 CHAR๋ ๋ถ์กฑํ ๊ณต๊ฐ์ ์คํ์ด์ค๋ก ์ฑ์ ๋ฃ์.
TEXT: ๊ธด ๊ธ์ ์ฌ์ฉํ ๋ ์ฌ์ฉ
- VARCHAR๋ ์๋ฐฑ ์ ์ด๋ด์ ๋ฌธ์์ด์ ์ฌ์ฉ.
TINYINT: -128๋ถํฐ 127๊น์ง์ ์ ์๋ฅผ ์ ์ฅํ ๋ ์ฌ์ฉ. 1๋๋ 0๋ง ์ ์ฅํ๋ค๋ฉด boolean๊ฐ์ ์ญํ .
DATETIME์ ๋ ์ง์ ์๊ฐ์ ๋ํ ์ ๋ณด๋ฅผ ๋ด๋๋ค.
AUTO_INCREMENT: ์์ฑ๋ ๋๋ง๋ค ์๋์ผ๋ก ์ซ์ 1 ์ฌ๋ฆผ.
ZEROFILL: ์ซ์์ ์๋ฆฟ์๊ฐ ๊ณ ์ ๋์ด ์์ ๋ ์ฌ์ฉ๋์ด ์์. ZEROFILL์ ํ๋ฉด ์ซ์๊ฐ ๋น์์ ๋ ๋ชจ๋ 0์ ๋ฃ๋๋ค
- INT(4)์ธ๋ฐ ์ซ์ 1์ ๋ฃ์๋ค๋ฉด 0001์ด ๋๋ค.
DEFAULT: MySQL ๊ธฐ๋ณธ๊ฐ์ ๋ฃ๋๋ค.
ํด๋น ์ปฌ๋ผ์ด ๊ธฐ๋ณธํค์ธ ๊ฒฝ์ฐ์ PRIMARY KEY ์ต์ ์ ์ค์
UNIQUE_INDEX: ๊ณ ์ ํด์ผ ํ๋์ง์ ๋ํ ์ต์ ์ด๋ฉฐ, PRIMARY KEY๋ UNIQUE INDEX์ ๊ฒฝ์ฐ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋ณ๋๋ก ์ปฌ๋ผ์ ๊ด๋ฆฌํ๋ฏ๋ก ์กฐํ ์ ์๋๊ฐ ๋นจ๋ผ์ง๋ค. ๊ธฐ๋ณธํค๋ ์ฌ์ค ๊ณ ์ ํด์ผ ํ์ง๋ง UNIQUE_INDEX๋ฅผ ์๋์ผ๋ก ํฌํจํ๋ฏ๋ก ๋ฐ๋ก ์ ์ง ์์๋ ๋๋ค.
COMMENT ํ ์ด๋ธ์ ๋ํ ๋ณด์ถฉ ์ค๋ช ์ ์๋ฏธ ํ ์ด๋ธ์ด ๋ฌด์จ ์ญํ ์ ํ๋์ง ์ ์ด๋๋ฉฐ ๋๊ณ , ํ์๋ ์๋๋ค.
ENGINE์ ์ฌ๋ฌ๊ฐ์ง ์๋ฏธ๊ฐ ์์ง๋ง MyISAM๊ณผ InnoDB ์ ์ผ ๋ง์ด ์ฌ์ฉ๋๋ค. ์ด๋ฒ์๋ InnoDB๋ฅผ ์์ง์ผ๋ก ์ฌ์ฉ.
์ํฌ๋ฒค์น๋ผ๋ ํด์ ์ธ๊ฑด๋ฐ, MySQL์ ์ง์ ์์ฑํ ์๋ ์์ง๋ง, ์ผ๋จ ๋ ธ๋js ์ด๋ป๊ฒ ์ฐ๋์ง๊ฐ ์ด์ ์ด๋ผ ์จํฌ๋ฒค์น ํด๋ก ๋๋ฑ๋๋ฑ ๋ง๋ค์ด๋ณด์.
PK: ํ๋ผ์ด๋จธ๋ฆฌ ํค ์ฌ๋ถ
NN: ๋น์นธ์ ํ์ฉํ ์ง ์ฌ๋ถ
UQ(์ ๋ํฌ ์ธ๋ฑ์ค)
UN์ Unsigned, ZF๋ ์ ๋ก ํ
Default/Expression์ ๊ธฐ๋ณธ๊ฐ์ ์ค์ ํด๋๋๊ฒ
Foreign Keys์์ CASCADE๋ฅผ ํด๋๋ฉด ๋ค๋ฅธ์ชฝ์์ ์ง์ฐ๊ฑฐ๋ ์ ๋ฐ์ดํธํ๋ฉด ์ฝ๋ฉํธ ํ ์ด๋ธ์๋ ๋ฐ์๋๋ค.
# CRUD ์์ฑํ๊ธฐ
Create, Read, Update, Delete์ ์ฝ์๋ก.
ํ์ด์ง ๋ค์ด์ ๊ตฌํ์ ํ์ํ OFFSET๋ง ๋ณด์.
OFFSET [๊ฑด๋๋ธ ์ซ์]
์ฒ์ 1~20์ ์กฐํํ๋ฉด ๋ค์์ 21์์ 40๊น์ง ์กฐํํ๋ค
mysql>
SELECT id, name FROM nodejs.users
ORDER BY age DESC
LIMIT 1
OFFSET 1;
update
UPDATE nodejs.users
SET comment = '๋ฐ๊ฟ ๋ด์ฉ' WHERE id = 2;
delete
DELETE FROM nodejs.users WHERE id = 2'
# ์ํ๋ผ์ด์ฆ ์ฌ์ฉํ๊ธฐ
์ํ๋ผ์ด์ฆ๋ ORM(Object-relational Mapping)์ผ๋ก ๋ถ๋ฅ๋๋ค. ORM์ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฆด๋ ์ด์ ์ ๋งคํํด์ฃผ๋ ๋๊ตฌ
์ํ๋ผ์ด์ฆ๋ฅผ ๋จ์ง MySQL๊ณผ ๊ฐ์ด์จ์ผํ๋๊ฑด ์๋๋ค. MariaDB, PostgreSQL, SQLite, MSSQL ๋ฑ ๋ค๋ฅธ ๋ฐ๋ฒ ๋๋ ๊ฐ์ด ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.์ํ๋ผ์ด์ฆ ์ฌ์ฉํ๋ ์ด์ ๋ SQL์ธ์ด๋ฅผ ์ง์ ์ฌ์ฉ์ํด๋ ์์ค๋ก ๋ฐ๊ฟ์ฃผ๊ธฐ ๋๋ฌธ.
npm i express morgan nunjucks sequelize sequelize-cli mysql2
npm i -D nodemon
sequelize-cli๋ ์ํ๋ผ์ด์ฆ ๋ช ๋ น์ด๋ฅผ ์คํํ๊ธฐ ์ํ ํจํค์ง์ด๋ฏ๋ก mysql2๋ MySQL๊ณผ ์ํ๋ผ์ด์ฆ๋ฅผ ์ด์ด์ฃผ๋ ๋๋ผ์ด๋ฒ์ด๋ค.
mysql2 ์์ฒด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ๋ก๊ทธ๋จ์ด ์๋๋ฏ๋ก ์คํดํ๋ฉด ์ ๋๋ค.
์ค์น ์๋ฃ ํ sequelize init ๋ช ๋ น์ด๋ฅผ ํธ์ถํ๋ฉด ์๋๋ค. ์ ์ญ ์ค์น ์์ด ๋ช ๋ น์ด๋ก ์ฌ์ฉํ๋ ค๋ฉด ์์ npx๋ฅผ ๋ถ์ด๋ฉด ๋๋ค.
npx sequelize init
config, models, migrations, seeders ํด๋๊ฐ ์์ฑ๋๋ค. models ํด๋ ์์ index.js๊ฐ ์์ฑ๋์๋์ง ํ์ธ sequelize-cli๊ฐ ์๋์ผ๋ก ์์ฑ๋๋ ์ฝ๋๋ ๊ทธ๋๋ก ์ฌ์ฉํ ๋ ์๋ฌ๊ฐ ๋ฐ์ํ๊ณ ํ์์๋ ๋ถ๋ถ๋ ๋ง์์ ์์ ํด ์ฃผ์ด์ผ ํ๋ค.
์ด๊ฑด ๋ค์ ๋์ค๋ฏ๋ก ๊ทธ๋ index.js ํ์ผ์ ๋ณด์
MySQL์ ์ ์ํ ๊ฑฐ ์ํ๋ผ์ด์ฆ์๋ ์ ์ํด ์ฃผ์ด์ผ ํ๋ค.
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, // โ
static initiate ๋ฉ์๋์ ๋งค๊ฐ๋ณ์์ ์ฐ๊ฒฐ๋๋ ์ต์
์ผ๋ก db.sequelize ๊ฐ์ฒด๋ฅผ ๋ฃ์ด์ผ ํ๋ค.
timestamps: false, // โ
true ์ํ๋ผ์ด์ฆ๊ฐ ์๋์ผ๋ก create_at๊ณผ update_at, timestamps ์์ฑ์ด ํ์ ์๋ค,
underscored: false, // โ
์ํ๋ผ์ด์ฆ ๊ธฐ๋ณธ์ ์ผ๋ก ํ
์ด๋ธ๋ช
๊ณผ ์นผ๋ผ๋ช
์ ์บ๋ฉ ์ผ์ด์ค๋ก ๋ง๋ ๋ค. ์ด๋ฅผ ์ค๋ค์ดํฌ ์ผ์ด์ค๋ก ๋ง๋๋ ๊ฑฐ๋ค.
modelName: 'User', // โ
๋ชจ๋ธ ์ด๋ฆ
tableName: 'users', // โ
๋ณดํต ์๋ฌธ์ ๋ฐ ๋ณต์ํ
paranoid: false, // โ
true๋ฉด deletedAt์ด๋ผ๋ ์นผ๋ผ ์๊น ๋ก์ฐ๋ฅผ ์ญ์ ํ ๋ ์์ ํ ์ง์์ง์ง ์๊ณ ์ง์ด ์๊ฐ ๊ธฐ๋ก. row ์กฐํ์ null์ธ ๊ฒ๋ง ์กฐํ๋๋ค. ๋์ค์ row ๋ณต์ํด์ผ ํ ๋.
charset: 'utf8', // โ
ํ๊ธ์
๋ ฅ ์ํด์
collate: 'utf8_general_ci', // โ
ํ๊ธ์
๋ ฅ ์ํด์
});
}
static associate(db) {
db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id' });
}
};
User ๋ชจ๋ธ์ ๋ง๋ค๊ณ ๋ชจ๋๋ก exportsํ๋ค. User ๋ชจ๋ธ์ Sequelize.Model์ ํ์ฅํ ํด๋์ค๋ก ์ ์ธํ๋ค.
ํด๋์ค ๋ฌธ๋ฒ์ ์ฌ์ฉํ์ง๋ง ํด๋์ค์ ๋ํ ์ง์์ด ์์ด๋ ์ฌ์ฉํ ์ ์๋ค.
static initate ๋ฉ์๋์ static associate ๋ฉ์๋๋ก ๋๋์ด ์ง๋๋ค.
๋ชจ๋ธ.init ๋ฉ์๋์ ์ฒซ ๋ฒ์งธ ์ธ์๊ฐ ํ ์ด๋ธ ์นผ๋ผ์ ๋ํ ์ค์ ์ด๊ณ , ๋ ๋ฒ์งธ ์ธ์๊ฐ ํ ์ด๋ธ ์์ฒด์ ๋ํ ์ค์
์ํ๋ผ์ด์ฆ๋ ์์์ id๋ฅผ ๊ธฐ๋ณธ ํค๋ก ์ฐ๊ฒฐํ๋ฏ๋ก id ์ปฌ๋ผ์ ์ ์ด์ค ํ์๊ฐ ์๋ค
๋๋จธ์ง ์ปฌ๋ผ์ ์คํ์ ์ ๋ ฅํ๋ค. MySQL์ ์๋ฃํ๊ณผ๋ ๋ค๋ฅผ ์ ๋ฐ์ ์๋ค.
๋จ, ์ํ๋ผ์ด์ฆ์ ์๋ฃํ์ MySQL์ ์๋ฃํ๊ณผ๋ ๋ค๋ฅด๋ค. ์ํ๋ผ์ด์ฆ๋ MySQL ์ด์ธ์ ๋ค๋ฅธ ๋ฐ๋ฒ ๋ ์ฒ๋ฆฌํ ์ ์์ด์ผ ํ๋ฏ๋ก MySQL์ ์๋ฃํ๊ณผ๋ ๋ค๋ฅผ ์ ๋ฐ์ ์๋ค.
VARCHAR๋ STRING์ผ๋ก
INT๋ INTEGER๋ก
TINYINT๋ BOOLEAN์ผ๋ก
DATETIME์ DATE๋ก ์ ๋๋ค.
INTEGER.UNSIGNED๋ UNSIGNED ์ต์ ์ด ์ ์ฉ๋ INT๋ฅผ ์๋ฏธํ๋ค. ์ฌ๊ธฐ์ ZEROFILL ์ต์ ๋ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด INTEGER.UNSIGNED.ZEROFILL์ ์ ๋๋ค.
allowNull์ NOT NULL ์ต์ ๊ณผ ๋์ผํ๋ค.
unique๋ UNIQUE ์ต์ ์ด๋ค.
defaultValue๋ ๊ธฐ๋ณธ๊ฐ(default)๋ฅผ ์๋ฏธํ๋ค. Squelize.NOW๋ก ํ์ฌ ์๊ฐ์ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ฉํ ์ ์๊ณ SQL now()์ ๊ฐ๋ค.
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' });
}
};
users ํ ์ด๋ธ๊ณผ ์ฐ๊ฒฐ๋ commenter ์นผ๋ผ์ด ์๋ค. ์ด ๋ถ๋ถ์ ๋ชจ๋ธ์ ์ ์ํ ๋ ๋ฃ์ด๋ ๋์ง๋ง ์ํ๋ผ์ด์ฆ ์์ฒด์์ ๊ด๊ณ๋ฅผ ๋ฐ๋ก ์ ์ํ ์ ์๋ค. ์ด์ ๋ํด์๋ ๋ค์์ ์์๋ณด์.
const Sequelize = require('sequelize');
const User = require('./user'); // โ
User์ Comment ๋ชจ๋ธ์ ๋ด์๋์๋ค.
const Comment = require('./comment'); // โ
User์ 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;
initiate ๋ฉ์๋๋ ๊ฐ๊ฐ์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค. ๋ชจ๋ธ.init์ด ์คํ๋์ด์ผ ํ ์ด๋ธ์ด ๋ชจ๋ธ๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.
๋ค๋ฅธ ํ ์ด๋ธ๊ณผ ๊ด๊ณ๋ฅผ ์ฐ๊ฒฐํ๋ static associate ๋ฉ์๋๋ ๋ฏธ๋ฆฌ ์คํํด๋๋ค.
# ๊ด๊ณ ์ ์ํ๊ธฐ
users์ comments ํ ์ด๋ธ ๊ฐ์ ๊ด๊ณ๋ฅผ ์ ์ํด๋ณด์.
ํด์ํ๊ทธ ๊ฐ์ ๊ฒฝ์ฐ๋ N: M ๊ด๊ณ
1:N ๊ด๊ณ
User -- hasMany --> Comment
User <-- belongsTo -- Comment
static associate(db) {
db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id' });
}
static associate(db) {
db.Comment.belongsTo(db.User, { foreignKey: 'commenter', targetKey: 'id' });
}
์ db๋ผ๋ ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ๋๋ฉด ์ต์๋จ์ const Comment = require('./comment')์์ผ๋ก ๋ถ๋ฌ์ค๋ฉด ์๋ ๊น ์๊ฐํ๋ ์ด ๊ฒฝ์ฐ์๋ ์ํ์ฐธ์กฐ๊ฐ ๋ฐ์ํจ.
index.js์์ ๊ฐ ๋ชจ๋ธ์ ๋ถ๋ฌ์ db๋ก ๋ถ๋ฌ์ ๋งค๊ฐ๋ณ์๋ก ๋๊ธฐ๋ ๋ฐฉ์์ ์ทจํจ.
foreignKey๋ก '๋ชจ๋ธ๋ช +๊ธฐ๋ณธ ํค'์ ์ปฌ๋ผ์ด ๋ชจ๋ธ์ ์์ฑ๋ฉ๋๋ค. ์๋ฅผ๋ค์ด commenter๋ฅผ ์ธ๋ ํค๋ก ๋ฃ์ด์ฃผ์ง ์์๋ค๋ฉด user(๋ชจ๋ธ๋ช ) +๊ธฐ๋ณธ ํค(id)๊ฐ ํฉ์ณ์ง userId๊ฐ ์ธ๋ํค๋ก ์์ฑ๋ฉ๋๋ค.
1:1
hasOne ์ฌ์ฉ.
User -- hasOne --> Info
User <-- belongsTo -- Info
static associate(db) {
db.User.hasOne(db.Info, { foreignKey: 'UserId', sourceKey: 'id' });
}
static associate(db) {
db.Info.belongsTo(db.User, { foreignKey: 'UserId', targetKey: 'id' });
}
N: M
static associate(db) {
db.Post.belongsToMany(db.HashTag, , { through: 'PostHashTag' });
}
static associate(db) {
db.HashTag.belongsToMany(db.Post, { through: 'PostHashTag' });
}
์์ชฝ ๋ชจ๋ธ ๋ชจ๋์ belongsToMany ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
PostHashTag ๋ชจ๋ธ์๋ ๊ฒ์๊ธ๊ณผ ํด์ํ๊ทธ์ ์์ด๋๊ฐ ์ ์ฅ๋๋ค.
N: M ๊ด๊ณ ํ ์ด๋ธ์์๋ ์กฐํํ ๋ ์ฌ๋ฌ ๋จ๊ณ๋ฅผ ๊ฑฐ์ณ์ผ ํจ.
#๋ ธ๋ ํด์ํ๊ทธ๋ฅผ ์ฌ์ฉํ ๊ฒ์๋ฌผ์ ์กฐํํ๋ ๊ฒฝ์ฐ ์๊ฐํด๋ณด์.
๋จผ์ #๋ ธ๋ ํด์ํ๊ทธ๋ฅผ Hashtag ๋ชจ๋ธ ์กฐํํ๊ณ ๊ฐ์ ธ์จ ํ๊ทธ์ ์์ด๋(1)์ ๋ฐํ์ผ๋ก PostHashtag ๋ชจ๋ธ์์ hastagId๊ฐ 1์ธ postId๋ค์ ์ฐพ์ Post ๋ชจ๋ธ์์ ๊ฐ์ ธ์จ๋ค.
์๋์ผ๋ก ๋ง๋ค์ด์ง ๋ชจ๋ธ๋ค๋ ๋ค์๊ณผ ๊ฐ์ด ์ ๊ทผํ ์ ์๋ค.
db.sequelize.models.PostHashtag
# ์ฟผ๋ฆฌ ์์๋ณด๊ธฐ
์ํ๋ผ์ด์ฆ CRUD ์์ ํ๋ ค๋ฉด ๋จผ์ ์ํ๋ผ์ด์ฆ ์ฟผ๋ฆฌ๋ฅผ ์์์ผ ํ๋ค. SQL๋ฌธ์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ์์ฑํ๋ ๊ฒ.
SQL๋ฌธ์ ์์ํ๋ ์ต์ ๋ค์ด ์์. ์ฟผ๋ฆฌ๋ ํ๋ก๋ฏธ์ค๋ฅผ ๋ฐํํ๋ฏ๋ก then์ ๋ถ์ฌ ๊ฒฐ๊ด๊ฐ์ ๋ฐ์ ์ ์๋ค. async/await ๋ฌธ๋ฒ๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ค.
๋ก์ฐ๋ฅผ ์์ฑํ๋ ์ฟผ๋ฆฌ๋ถํฐ ์์๋ณด์.
INSERT INTO nodejs.users (name, age, married, comment) VALUES ('zero', 24, 0, '์๊ฐ์๊ฐ1');
const { User } = require('../models');
User.create({
name: 'zero',
age: 24,
married: false,
comment: '์๊ธฐ์๊ฐ1'
})
models ๋ชจ๋์์ User ๋ชจ๋ธ์ ๋ถ๋ฌ์ create ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
์์ผ๋ก๋ User ๋ชจ๋ธ์ ๋ถ๋ฌ์๋ค๋ ์ ์ ํ์ ์๊ฐํฉ๋๋ค.
์ํ๋ผ์ด์ฆ ๋ชจ๋ธ์ MySQL์ด ์๋๋ผ ์ ์ํ ์๋ฃํ๋๋ก ๋ฃ์ด์ผ ํ๋ค.
์ด๊ฒ์ด married๊ฐ 0์ด ์๋๋ผ false์ธ ์ด์ .
์๋ฃํ์ด๋ ์ต์ ์ ๋ถํฉํ์ง ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์์ ๋๋ ์ํ๋ผ์ด์ฆ๊ฐ ์๋ฌ๋ฅผ ๋ฐ์์ํจ๋ค.
๋ค์์ users ํ ์ด๋ธ์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ SQL๋ฌธ์ด๋ค.
SELECT * FROM nodejs.users;
User.findAll({});
๋ค์์ ํ๋๋ง ๊ฐ์ ธ์ค๋๊ฑฐ๋ค.
SELECT * FROM nodejs.users LIMIT 1;
User.findOne({});โ
attributes ์ต์ ์ฌ์ฉํด์ ์ํ๋ ์ปฌ๋ผ๋ง ๊ฐ์ ธ์ฌ ์ ์๋ค.
SELECT name, married FROM nodejs.users;
User.findAll({
attributes: ['name', 'married'],
});
where ์ต์ ์ด ์กฐ๊ฑด๋ค์ ๋์ดํ๋ ์ต์
SELECT name, age FROM nodejs.users WHERE marreid = 1 AND age > 30;
const { Op } = require('sequelize');
const { User } = require('../models');
User.findAll({
attributes: ['name', 'age'],
where: {
married: true,
age: { [Op.gt]: 30 }, // ES2015 ๋ฌธ๋ฒ์ด๋ค. ํน์ ์ฐ์ฐ์์ธ๋ฐ ์ํ๋ผ์ด์ฆ ๋ด๋ถ์ Op๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์จ๋ค.
},
});
Op.gt(์ด๊ณผ), Op.gte(์ด์), Op.1t(๋ฏธ๋ง), Op.1te(์ดํ), Op.ne(๊ฐ์ง ์์), Op.or(๋๋), Op.in(๋ฐฐ์ด ์์ ์ค ํ๋), Op.notIn(๋ฐฐ์ด ์์์ ๋ชจ๋ ๋ค๋ฆ) ๋ฑ
SELECT id, name FROM users ORDER BY age DESC;
User.findAll({
attrigutes: ['id', 'name'],
order: [['age', 'DESC']],
limit: 1,
});
์ํ๋ผ์ด์ฆ์ ์ ๋ ฌ ๋ฐฉ์์. ์ ๋ ฌ์ ๊ผญ ์นผ๋ผ ํ๋๋ก๋ง ํ๋๊ฒ ์๋. ์ ํ๋ ํ ์ ์๋ค.
SELECT id, name FROM users ORDER BY age DESC LIMIT 1 OFFSET 1;
User.findAll({
attributes: ['id', 'name'],
order: ['age, 'DESC'],
limit: 1,
offset: 1,
});
๋ฆฌ๋ฐ๋ง๊ณ ์คํ์ ์ผ๋ก๋ ๊ตฌํ ๊ฐ๋ฅ
์ด๋ฒ์๋ ๋ก์ฐ๋ฅผ ์์ ํ๋ ์ฟผ๋ฆฌ.
SELECT nodejs.users SET comment = '๋ฐ๊ฟ ๋ด์ฉ' WHERE id = 2;
User.update({
comment: '๋ฐ๊ฟ ๋ด์ฉ'
}, {
where: { id: 2 },
});
๋ฉ์๋๋ฅผ ์ด๋ ๊ฒ ์์ ํ ์๋ ์๋ค.
์ด๋ฒ์๋ ์ญ์ ํด๋ณด์. ์กฐ๊ฑด where์ ๊ฑธ์ด์ ์ญ์ ๊ฐ๋ฅ
DELETE FROM nodejs.users WHERE id = 2;
User.detroy({
where: { id: 2 },
});
findOne์ด๋ findAll ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ ํ๋ก๋ฏธ์ค์ ๊ฒฐ๊ณผ๋ก ๋ชจ๋ธ์ ๋ฐํํ๋ค.
const user = await User.findOne({});
console.log(user.nick); // ์ฌ์ฉ์ ๋๋ค์.
User ๋ชจ๋ธ์ ์ ๋ณด์๋ ๋ฐ๋ก ์ ๊ทผํ ์ ์์ง๋ง ๋ ํธ๋ฆฌํ ์ ์ ๊ด๊ณ ์ฟผ๋ฆฌ๋ฅผ ์ง์ํ๋ค๋ ๊ฒ์ด๋ค.
MySQL๋ก ๋ฐ์ง๋ฉด JOIN ๊ธฐ๋ฅ์ด๋ค. ๋ง์ฝ ํน์ ์ฌ์ฉ์๋ฅผ ๊ฐ์ ธ์ค๋ฉด์ ๊ทธ ์ฌ๋์ ๋๊ธ๊น์ง ๋ชจ๋ ๊ฐ์ ธ์ค๊ณ ์ถ๋ค๋ฉด?
include์ฌ์ฉํด์ ๊ฐ์ ธ์จ๋ค.
const user = await User.findOne({
include: [{
model: Comment,
}]
});
console.log(user.Comments); // ์ฌ์ฉ์ ๋๊ธ
์ด๋ค ๋ชจ๋ธ๊ณผ ๊ด๊ณ๊ฐ ์๋์ง๋ฅผ include ๋ฐฐ์ด์ ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
๋ฐฐ์ด์ธ ์ด์ ๋ ๋ค์ํ ๋ชจ๋ธ๊ณผ ๊ด๊ณ๊ฐ ์์ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋๊ธ์ ์ฌ๋ฌ ๊ฐ์ผ ์ ์์ผ๋ฏ๋ก
const user = await User.findOne{()};
const comments = await user.getComments();
console.log(comments); // ์ฌ์ฉ์ ๋๊ธ
๊ด๊ณ๋ฅผ ์ค์ ํ๋ค๋ฉด getComments(์กฐํ) ์ธ์๋ setComments(์์ ) addComment(ํ๋ ์์ฑ), addComments(์ฌ๋ฌ ๊ฐ ์์ฑ), removeComments(์ญ์ ) ๋ฉ์๋๋ฅผ ์ง์
๋์ฌ ๋ค์ ๋ชจ๋ธ์ด ๋ถ๋ ํ์
// ๊ด๊ณ ์ค์ ํ ๋ as๋ก ๋ฑ๋ก
db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id', as: 'Answer'});
// ์ฟผ๋ฆฌํ ๋๋
const user = await User.findOne{()};
const comments = await user.getAnswers();
console.log(comments); // ์ฌ์ฉ์ ๋๊ธ
as๋ฅผ ์ค์ ํ๋ฉด includeํ ๋ ์ถ๊ฐ๋๋ ๋๊ธ ๊ฐ์ฒด๋ user.Answers๋ก ๋ฐ๋๋๋ค.
include๋ ๊ด๊ณ ์ฟผ๋ฆฌ ๋ฉ์๋์๋ where์ด๋ attributes ๊ฐ์ ์ต์ ์ ์ฌ์ฉํ ์ ์๋ค.
const user = await User.findOne({
include: [{
model: Comment,
where: {
id: 1,
attributes: ['id'],
}]
});
// or
const comments = await user.getComments({
where: {
id: 1,
},
attributes: ['id'],
});
๋๊ธ์ ๊ฐ์ ธ์ฌ ๋๋ id๊ฐ 1์ธ ๋๊ธ๋ง ๊ฐ์ ธ์ค๊ณ , ์ปฌ๋ผ๋ id ์ปฌ๋ผ๋ง ๊ฐ์ ธ์ค๋๋ก ํ๊ณ ์๋ค.
๊ด๊ณ ์ฟผ๋ฆฌ ์ ์กฐํ๋ ์์ ๊ฐ์ด ํ์ง๋ง ์์ , ์์ฑ, ์ญ์ ๋๋ ์กฐ๊ธ ๋ค๋ฅธ ์ ์ด ์๋ค.
const user = await User.findOne({});
const comment = await Comment.create();
await user.addComment(comment);
// ๋๋
await user.addComment(comment.id);
// โ
์ฌ๋ฌ๊ฐ ์ถ๊ฐ์ ๋ฐฐ์ด๋ก ๊ฐ๋ฅ
const user = await User.findOne({});
const comment1 = await Comment.create();
const comment2 = await Comment.create();
await user.addComment([comment1, comment2]);
๊ด๊ณ ์ฟผ๋ฆฌ ๋ฉ์๋์ ์ธ์๋ก ์ถ๊ฐํ ๋๊ธ ๋ชจ๋ธ์ ๋ฃ๊ฑฐ๋ ๋๊ธ์ ์์ด๋๋ฅผ ๋ฃ์ผ๋ฉด ๋๋ค. ์์ ์ญ์ ๋ ๋ง์ฐฌ๊ฐ์ง
SQL ์ฟผ๋ฆฌํ๊ธฐ
๋ง์ฝ ์ํ๋ผ์ด์ฆ ์ฌ์ฉํ๊ธฐ ์ซ๊ฑฐ๋ ์ด๋ป๊ฒ ํด์ผํ ์ง ๋ชจ๋ฅด๋ค๋ฉด ์ง์ SQL ์ฌ์ฉํด์ผํ๋ค.
const [result, metadata] = await sequelize.query('SELECT * from commnets');
console.log(result);
์ฌ๋งํ๋ฉด ์ํ๋ผ์ด์ฆ์ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋๊ฑฐ ์ถ์ฒํ์ง๋ง ์ํ๋ผ์ด์ฆ ์ฟผ๋ฆฌ๋ก ํ ์ ์๋ ๊ฒฝ์ฐ์๋ ์์ ๊ฐ์ด ํ๋ฉด ๋๋ค.
# ์ฟผ๋ฆฌ ์ํํ๊ธฐ
๋ชจ๋ธ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ํ์ด์ง๋ฅผ ๋ ๋๋งํ๋ ๋ฐฉ๋ฒ๊ณผ JOSN ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ๊ณผ JSON ํ์์ผ๋ก ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ์ ์์๋ณด์.
๊ฐ๋จํ๊ฒ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฑ๋กํ๊ณ ์ฌ์ฉ์๊ฐ ๋ฑ๋กํ ๋๊ธ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
// ์ฌ์ฉ์ ์ด๋ฆ ๋๋ ์ ๋ ๋๊ธ ๋ก๋ฉ
document.querySelectorAll('#user-list tr').forEach((el) => {
el.addEventListener('click', function () {
const id = el.querySelector('td').textContent;
getComment(id);
});
});
// ์ฌ์ฉ์ ๋ก๋ฉ
async function getUser() {
try {
const res = await axios.get('/users');
const users = res.data;
console.log(users);
const tbody = document.querySelector('#user-list tbody');
tbody.innerHTML = '';
users.map(function (user) {
const row = document.createElement('tr');
row.addEventListener('click', () => {
getComment(user.id);
});
// ๋ก์ฐ ์
์ถ๊ฐ
let td = document.createElement('td');
td.textContent = user.id;
row.appendChild(td);
td = document.createElement('td');
td.textContent = user.name;
row.appendChild(td);
td = document.createElement('td');
td.textContent = user.age;
row.appendChild(td);
td = document.createElement('td');
td.textContent = user.married ? '๊ธฐํผ' : '๋ฏธํผ';
row.appendChild(td);
tbody.appendChild(row);
});
} catch (err) {
console.error(err);
}
}
// ๋๊ธ ๋ก๋ฉ
async function getComment(id) {
try {
const res = await axios.get(`/users/${id}/comments`);
const comments = res.data;
const tbody = document.querySelector('#comment-list tbody');
tbody.innerHTML = '';
comments.map(function (comment) {
// ๋ก์ฐ ์
์ถ๊ฐ
const row = document.createElement('tr');
let td = document.createElement('td');
td.textContent = comment.id;
row.appendChild(td);
td = document.createElement('td');
td.textContent = comment.User.name;
row.appendChild(td);
td = document.createElement('td');
td.textContent = comment.comment;
row.appendChild(td);
const edit = document.createElement('button');
edit.textContent = '์์ ';
edit.addEventListener('click', async () => { // ์์ ํด๋ฆญ ์
const newComment = prompt('๋ฐ๊ฟ ๋ด์ฉ์ ์
๋ ฅํ์ธ์');
if (!newComment) {
return alert('๋ด์ฉ์ ๋ฐ๋์ ์
๋ ฅํ์
์ผ ํฉ๋๋ค');
}
try {
await axios.patch(`/comments/${comment.id}`, { comment: newComment });
getComment(id);
} catch (err) {
console.error(err);
}
});
const remove = document.createElement('button');
remove.textContent = '์ญ์ ';
remove.addEventListener('click', async () => { // ์ญ์ ํด๋ฆญ ์
try {
await axios.delete(`/comments/${comment.id}`);
getComment(id);
} catch (err) {
console.error(err);
}
});
// ๋ฒํผ ์ถ๊ฐ
td = document.createElement('td');
td.appendChild(edit);
row.appendChild(td);
td = document.createElement('td');
td.appendChild(remove);
row.appendChild(td);
tbody.appendChild(row);
});
} catch (err) {
console.error(err);
}
}
// ์ฌ์ฉ์ ๋ฑ๋ก ์
document.getElementById('user-form').addEventListener('submit', async (e) => {
e.preventDefault();
const name = e.target.username.value;
const age = e.target.age.value;
const married = e.target.married.checked;
if (!name) {
return alert('์ด๋ฆ์ ์
๋ ฅํ์ธ์');
}
if (!age) {
return alert('๋์ด๋ฅผ ์
๋ ฅํ์ธ์');
}
try {
await axios.post('/users', { name, age, married });
getUser();
} catch (err) {
console.error(err);
}
e.target.username.value = '';
e.target.age.value = '';
e.target.married.checked = false;
});
// ๋๊ธ ๋ฑ๋ก ์
document.getElementById('comment-form').addEventListener('submit', async (e) => {
e.preventDefault();
const id = e.target.userid.value;
const comment = e.target.comment.value;
if (!id) {
return alert('์์ด๋๋ฅผ ์
๋ ฅํ์ธ์');
}
if (!comment) {
return alert('๋๊ธ์ ์
๋ ฅํ์ธ์');
}
try {
await axios.post('/comments', { id, comment });
getComment(id);
} catch (err) {
console.error(err);
}
e.target.userid.value = '';
e.target.comment.value = '';
});
์ ์ด๋ ต๋ค! ์ผ๋จ ํ ์ฝ๊ณ ๋์ด๊ฐ๋ณด์
๋ผ์ฐํฐ๋ค์ ๋ฏธ๋ฆฌ 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'), '๋ฒ ํฌํธ์์ ๋๊ธฐ ์ค');
});
๋ผ์ฐํฐ์ ๋ด์ฉ์ sequlize.js์ ๋์ค๋ GET, POST, PUT, DELETE ์์ฒญ์ ํด๋นํ๋ ๋ผ์ฐํฐ๋ฅผ ๋ง๋ ๋ค. routes ํด๋๋ฅผ ๋ง๋ค๊ณ ๊ทธ ์์ index.js๋ฅผ ์์ฑํ๋ฉด ๋๋ค.
// 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;
๋จผ์ GET /๋ก ์ ์ํ์ ๋์ ๋ผ์ฐํฐ์ ๋๋ค. User.findAll ๋ฉ์๋๋ก ๋ชจ๋ ์ฌ์ฉ์๋ฅผ ์ฐพ์ ํ sequelize.html์ ๋ ๋๋งํ ๋ ๊ฒฐ๊ณผ๊ฐ์ธ uses๋ฅผ ๋ฃ์ต๋๋ค. ์ํ๋ผ์ด์ฆ๋ ํ๋ก๋ฏธ์ค๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ํ๋ฏ๋ก async/await๊ณผ try/catch๋ฌธ์ ์ฌ์ฉํด์ ๊ฐ๊ฐ ์กฐํ ์ฑ๊ณต์์ ์คํจ์์ ์ ๋ณด๋ฅผ ์ป์ ์ ์๋ค
๋ค์์ user.js๋ค. router.route('/')๋ก ๊ฐ์ ๊ฒฝ๋ก๋ ํ๋๋ก ๋ฌถ์๋ค.
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;
GET /users์ POST /users ์ฃผ์๋ก ์์ฒญ์ด ๋ค์ด์ฌ ๋์ ๋ผ์ฐํฐ์ด๋ค.
๊ฐ๊ฐ ์ฌ์ฉ์๋ฅผ ์กฐํํ๋ ์์ฒญ๊ณผ ๋ฑ๋กํ๋ ์์ฒญ์ ์ฒ๋ฆฌํ๋ค. GET /์์๋ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ์ง๋ง, GET /users์์๋ ๋ฐ์ดํฐ๋ฅผ JSON ํ์์ผ๋ก ๋ฐํํ๋ค๋ ๊ฒ์ ์ฐจ์ด๊ฐ ์๋ค.
GET /users/id:/comments ๋ผ์ฐํฐ์๋ findAll ๋ฉ์๋์ ์ถ๊ฐ๋์ด ์๋ค.
include ์ต์ ์์๋ model ์์ฑ์๋ User ๋ชจ๋ธ์, where ์์ฑ์๋ :id๋ก ๋ฐ์ ์์ด๋ ๊ฐ์ ๋ฃ๋๋ค.
:id๋ ๋ผ์ฐํธ ๋งค๊ฐ๋ณ์๋ req.params.id๋ก ๊ฐ์ ๊ฐ์ ธ์ฌ ์ ์๋ค.
GET /users/1/comments๋ผ๋ฉด ์ฌ์ฉ์ id๊ฐ 1์ธ ๋๊ธ์ ๋ถ๋ฌ์ค์. ์กฐํ๋ ๋๊ธ ๊ฐ์ฒด์๋ include๋ก ๋ฃ์ด์ค ์ฌ์ฉ์ ์ ๋ณด๋ ๋ค์ด์์ด์ ์์ฑ์์ ์ด๋ฆ์ด๋ ๋์ด ๋ฑ๋ ์กฐํ ๊ฐ๋ฅํ๋ค.
๋ค์์ 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;
๋๊ธ์ CRUD ์์ ์ ํ๋ ๋ผ์ฐํฐ๋ค. POST /comments, PATCH /comments/:id, DELETE/comments/:id๋ฅผ ๋ฑ๋ก
์ด์ npm start๋ก ์๋ฒ๋ฅผ ์คํํ๊ณ ์ํ๋ผ์ด์ฆ๊ฐ ์ํํ๋ SQL๋ฌธ์ด ๋์ค๋ฏ๋ก ์ด๋ค ๋์์ ํ๋์ง ํ์ธํ ์ ์๋ค.
SQL ๊ตฌ๋ฌธ์ด ๋ณด๊ณ ์ถ์ง ์๋ค๋ฉด config/config.json์ dialect ์์ฑ ใ ฃใ ์ "logging": false๋ฅผ ์ถ๊ฐํ๋ฉด ๋๋ค.
์ ์ ์ GET / ๋ผ์ฐํฐ์์ User.findAll ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฏ๋ก ๊ทธ์ ๋ฐ๋ฅธ SQL๋ฌธ์ด ์คํ๋๋ ๋ชจ์ต์ด๋ค.
'๐ฐ๏ธ Node.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Node.js] ๋ชฝ๊ณ ๋๋น (0) | 2023.08.10 |
---|---|
[Node.js] #6 ์ต์คํ๋ ์ค ์น ์๋ฒ ๋ง๋ค๊ธฐ (0) | 2023.07.23 |
[Node.js] #5 ํจํค์ง ๋งค๋์ (0) | 2023.07.23 |
[Node.js] #4 http ๋ชจ๋๋ก ์๋ฒ ๋ง๋ค๊ธฐ (0) | 2023.07.22 |
[Node.js] #3 ๋ ธ๋ ๊ธฐ๋ฅ ์์๋ณด๊ธฐ (0) | 2023.07.22 |