1. Sequelize ์
์
2. ๋ชจ๋ธ ์ ์ํ๊ธฐ2-1. index.js์ ๋ชจ๋ธ ์ฐ๊ฒฐ3. ๊ด๊ณ ์ ์1:1 ๊ด๊ณN:M ๊ด๊ณ4. ์ฟผ๋ฆฌCRUDSelectJOINRaw SQLTransaction
1. Sequelize ์ ์
npm i express sequelize sequelize-cli mysql2
npx sequelize init
: config, models, migrations, seeders ํด๋ ์์ฑ(sequelize-cli๊ฐ ์๋์ผ๋ก ๋ง๋ค์ด์ค)
- models/index.js ์๋์ ๊ฐ์ด ์์
const Sequelize = require('sequelize'); 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; module.exports = db;
{ "development": { "username": "root", "password": "1234", "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" } }
- app.js์์ sequelize์ด์ฉํ์ฌ db ์ฐ๊ฒฐ
const { sequelize } = require('./models'); sequelize.sync({force: false }) .then(() => { console.log('๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ฑ๊ณต'); }) .catch((err) => { console.error(err); });
2. ๋ชจ๋ธ ์ ์ํ๊ธฐ
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) {} };
- User ๋ชจ๋ธ๋ก ๋ง๋ค๊ณ exportsํจ
- Sequelize.Model์ ํ์ฅํ ํด๋์ค๋ก ์ ์ธ
- static init ๋ฉ์๋, static associate ๋ฉ์๋๋ก ๊ตฌ์ฑ๋จ
- static init ๋ฉ์๋ : ํ ์ด๋ธ์ ๋ํ ์ค์
- ์ฒซ ๋ฒ์งธ ์ธ์ : ํ ์ด๋ธ ์ปฌ๋ผ ์ค์
- ๋ ๋ฒ์งธ ์ธ์ : ํ ์ด๋ธ ์์ฒด์ ๋ํ ์ค์
- timestamps : true โ createdAt๊ณผ updatedAt ์ปฌ๋ผ ์๋ ์ถ๊ฐ
- underscored: ํ ์ด๋ธ๋ช , ์ปฌ๋ผ๋ช ๊ธฐ๋ณธ์ camel case. ์ด๋ฅผ ์ค๋ค์ดํฌ ์ผ์ด์ค๋ก ๋ฐ๊พธ์ด์ค. true๋ฉด
- paranoid: true๋ก ์ค์ ํ๋ฉด deletedAt ์ด๋ผ๋ ์ปฌ๋ผ์ด ์๊น. ๋ก์ฐ๋ฅผ ์ญ์ ํ ๋ ์์ ํ ์ง์์ง์ง ์๊ณ deletedAt์ ์ง์ด ์๊ฐ์ด ๊ธฐ๋ก๋จ
- charset, collate : utf8, utf8_general_ci๋ก ์ค์ ํด์ผ ํ๊ธ ์ ๋ ฅ๋จ
- ์์์ id๋ฅผ ๊ธฐ๋ณธ ํค๋ก ์ฐ๊ฒฐํ๋ฏ๋ก id ์ปฌ๋ผ์ ์ ์ด์ค ํ์๊ฐ ์์
- associate : ๋ค๋ฅธ ๋ชจ๋ธ๊ณผ์ ๊ด๊ณ
ํ์
๋น๊ต | MySQL | ์ํ๋ผ์ด์ฆ |
ใ
ค | VARCHAR(100) | STRING(100) |
ใ
ค | INT | INTEGER |
ใ
ค | TINYINT | BOOLEAN |
ใ
ค | DATETIME | DATE |
ใ
ค | INT UNSIGNED | INTEGER.UNSIGNED |
ใ
ค | NOT NULL | allowNull: false |
ใ
ค | UNIQUE | unique: true |
ใ
ค | DEFAULT now() | defaultValue: Sequelize.NOW |
2-1. 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.User = User; db.Comment = Comment; User.init(sequelize); Comment.init(sequelize); User.associate(db); Comment.associate(db); module.exports = db;
3. ๊ด๊ณ ์ ์
// User : Comment = 1 : N ๊ด๊ณ static associate(db) { db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id' }); } static associate(db) { db.Comment.belongsTo(db.User, { foreignKey: 'commenter', targetKey: 'id'}); }
- foreignKey๊ฐ ์๊ธฐ๋ ํ ์ด๋ธ์์ belongsTo๋ฅผ ํธ์ถ โ ์ฆ Comment ํ ์ด๋ธ์ commenter foreignKey ์ถ๊ฐ๋จ
- sourceKey์ id์ targetKey์ id ๋ชจ๋ User ๋ชจ๋ธ์ id ์
1:1 ๊ด๊ณ
db.User.hasOne(db.Info, { foreignKey: 'UserId', sourceKey: 'id' }); db.Info.belongsTo(db.User, { foreignKey: 'UserId', targetKey: 'id' });
- belongsTo๋ฅผ ์ฌ์ฉํ๋ Info ๋ชจ๋ธ์ UserId ์ปฌ๋ผ์ด ์ถ๊ฐ๋จ
N:M ๊ด๊ณ
db.Post.belongsToMany(db.Hashtag, { through: 'PostHashtag' }); db.Hashtag.belongsToMany(db.Post, { through: 'PostHashtag' });
- N : M ๊ด๊ณ ํน์ฑ์ ์๋ก์ด ๋ชจ๋ธ์ด ์์ฑ๋จ. through ์์ฑ์ ์๋ก์ด ๋ชจ๋ธ์ ์ด๋ฆ์ด ๋ช ์๋จ
- ์๋ก ์์ฑ๋ PostHashtag ๋ชจ๋ธ์ ๊ฒ์๊ธ๊ณผ ํด์ํ๊ทธ์ ์์ด๋๊ฐ ์ ์ฅ๋จ
- ์ฆ 1: N, M : 1 ๋ก ํผ๋ค๋ ์๋ฏธ
4. ์ฟผ๋ฆฌ
CRUD
/* db.sequelize = sequelize; db.User = User; db.Comment = Comment; User.init(sequelize); Comment.init(sequelize); User.associate(db); Comment.associate(db); module.exports = db; */ const { User } = require('../models'); // Create User.create({ name: 'zero', age: 24, married: false, comment: '์๊ธฐ์๊ฐ1', }); // Read User.findAll({}); User.findOne({}); User.findAll({ attributes: ['name', 'married'], }); // select name, married from nodejs.users; const { Op } = require('sequelize'); const { User } = require('../models'); User.findAll({ attributes: ['name', 'age'], where: { married: true, // Mysql ์์ undefined ์ง์ํ์ง ์์ผ๋, ๋น ๊ฐ๋ฃ์ผ๋ ค๋ฉด null๋ก ๋ฃ์ด์ผ ํจ age: { [Op.gt]: 30 }, }, }); User.findAll({ attributes: ['id', 'name'], where: { [Op.or]: [{ married: false }, { age: {[Op.gt]: 30} }], }, }); User.findAll({ attributes: ['id', 'name'], order: ['age', 'DESC'], limit: 1, offset: 1, }); // Update User.update({ comment: '๋ฐ๊ฟ ๋ด์ฉ', }, { where: { id : 2}, }); // Delete User.destroy({ where: { id : 2 }, });
Select
- attributes๋ nested array๋ฅผ ํตํด renaming์ด ๊ฐ๋ฅํจ
Model.findAll({ attributes: ['foo', ['bar', 'baz'], 'qux'] });
sequelize.fn
์ ์ด์ฉํด์ aggregation ๋ ๊ฐ๋ฅ
User.findAll({ attributes: [ 'workspaceId', 'workspaceZoneId', [sequelize.fn('COUNT', 'workspaceId'), 'workspaceCount'], [sequelize.fn('COUNT', 'workspaceZoneId'), 'workspaceZoneCount'], ], group: ['workspaceId', 'workspaceZoneId'], where: { organizationId: organizationId, connected: true, workspaceId: Array.from(workspaceMap.keys()) }, raw: true, // Return raw result. See sequelize.query for more information. }); // according SQL SELECT `workspace_id` AS `workspaceId`, `workspace_zone_id` AS `workspaceZoneId`, COUNT('workspaceId') AS `workspaceCount`, COUNT('workspaceZoneId') AS `workspaceZoneCount` FROM `users` AS `User` WHERE `User`.`connected` = true AND `User`.`organization_id` = 1 AND `User`.`workspace_id` IN (1, 2, 3, 4, 5) GROUP BY `workspaceId`, `workspaceZoneId`;
raw ์ต์ [์ฐธ๊ณ ]
raw ์ต์
์ด true ๋ฉด ๋ฐ์ดํฐ๊ฐ ๊ทธ๋๋ก ๋ฐํ๋๊ฒ ๋๊ณ
raw : false โ Model ๊ฐ์ฒด๋ก ๊ฐ์ธ์ ธ ์๊ธฐ ๋๋ฌธ์, get() ๋ฉ์๋ ํธ์ถํด์ผ ๋ฐ์ดํฐ์ ์ ๊ทผ์ด ๊ฐ๋ฅํจ


JOIN
const user = await User.findOne({ include : [{ model : Comment, }] }); // ๋๋ ๋ค์๊ณผ ๊ฐ์ด ๊ฐ์ ธ์ฌ ์ ์์ const user = await User.findOne({}); const comments = await user.getComments(); console.log(comments);
- ์ด๋ค ๋ชจ๋ธ๊ณผ ๊ด๊ณ๊ฐ ์๋์ง๋ฅผ include ๋ฐฐ์ด์ ๋ฃ์ด์ฃผ๋ฉด ๋จ
Raw SQL
const [result, metadata] = await sequelize.query('SELECT * from comments'); console.log(result);
Transaction
[ Sequelize ] Transaction
- Sequelize.transaction() ์ผ๋ก transaction ๋ง๋ค ์ ์์
- Model์ ๋ฉ์๋์ options.transaction ์ผ๋ก ํด๋น transaction์ ๋ช ์ํด์ ํธ๋์ญ์ ์์์ ์ฟผ๋ฆฌ ์คํ๋๋๋ก ์ค์ ๊ฐ๋ฅํจ
let workspace = await Workspace.findOne({ where: { id: workspaceId, organizationId: organizationId }, transaction: t, });