우리는 앞서 ORM이라는 것을 배웠다. 이 ORM을 구현하기 쉽게 해주는 라이브러리가 바로 Sequelize이다.
node.js에서 SQL문을 사용하지 않고 DB를 조작할 수 있게 해주는 라이브러리
Sequelize를 사용 시에는 항상 메소드가 비동기로 작동한다는걸 반드시 알아야 한다.
먼저 아래 명령어를 CLI에 실행시켜 Secquelize
를 설치해준다.
npm install --save squelize
npm install --save-dev sequelize-cli
npx sequelize-cli init
위 명령어들은 순서대로
이 명령어들을 순서대로 실행해준다.
모든 명령어를 실행하면
config/config.json models/ migrations/ seeders/
다음 4개의 파일 및 폴더들이 생성 된다.
이 후 데이터베이스와 연결을 해준다.
// 생성된 config/config.json 파일
{
"development": {
"username": "root",
"password": null,
"database": "database_development",
"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"
}
}
여기에 각각 이름에 맞는 데이터 베이스를 생성해주고 password
와 username
을 설정해준다.
이제 모든 준비는 끝났으니 제일먼저 모델을 정의해 보자.
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory:');
const User = sequelize.define('User', {
// 모델의 속성을 여기 정의해 준다.
firstName: {
type: DataTypes.STRING,
allowNull: false //null 값 허용 X
},
lastName: {
type: DataTypes.STRING
// null 값 허용
}
}, {
// ...
});
// 둘은 같다.
console.log(User === sequelize.models.User); // true
다음과 같은 형식을 통해서 모델을 정의할 수 있다.
그리고 확장된 방식은 다음과 같다.
const { Sequelize, DataTypes, Model } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory');
class User extends Model {} // User 클래스 생성 (Model을 상속)
User.init({
// 모델 속성 정의
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING
// null 값 허용
}
}, {
// 다른 모델 옵션들
sequelize, // 연결 인스턴스를 전달
modelName: 'User' // 모델이름 정의
});
// 둘은 같다.
console.log(User === sequelize.models.User); // true
npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string
--name <모델이름 작성>
--attributes <속성 : 타입>, <속성 : 타입>, ...
형식으로 작성해준다.
// Create a new user
const jane = await User.create({ firstName: "Jane", lastName: "Doe" });
// Find all users
const users = await User.findAll();
Model.findAll({
attributes: ['foo', 'bar']
});
// === SELECT foo, bar FROM Model
Model.findAll({
attributes: ['foo', ['bar', 'baz'], 'qux']
});
// === SELECT foo, bar AS baz, qux FROM ...
Model.findAll({
attributes: [
'foo',
[sequelize.fn('COUNT', sequelize.col('hats')), 'n_hats'],
'bar'
]
});
// === SELECT foo, COUNT(hats) AS n_hats, bar FROM ...
const { Op } = require("sequelize");
Post.findAll({
where: {
authorId: {
[Op.eq]: 2
}
}
});
// === SELECT * FROM post WHERE authorId = 2
Post.findAll({
where: {
authorId: 12
status: 'active'
}
});
// === SELECT * FROM post WHERE authorId = 12 AND status = 'active';
// AND 사용법
const { Op } = require("sequelize");
Post.findAll({
where: {
[Op.and]: [
{ authorId: 12 },
{ status: 'active' }
]
}
});
// === SELECT * FROM post WHERE authorId = 12 AND status = 'active';
// OR 사용법
const { Op } = require("sequelize");
Post.findAll({
where: {
[Op.or]: [
{ authorId: 12 },
{ authorId: 13 }
]
}
});
// === SELECT * FROM post WHERE authorId = 12 OR authorId = 13;
const { Op } = require("sequelize");
Post.findAll({
where: {
[Op.and]: [{ a: 5 }, { b: 6 }], // (a = 5) AND (b = 6)
[Op.or]: [{ a: 5 }, { b: 6 }], // (a = 5) OR (b = 6)
someAttribute: {
// Basics
[Op.eq]: 3, // = 3
[Op.ne]: 20, // != 20
[Op.is]: null, // IS NULL
[Op.not]: true, // IS NOT TRUE
[Op.or]: [5, 6], // (someAttribute = 5) OR (someAttribute = 6)
// Using dialect specific column identifiers (PG in the following example):
[Op.col]: 'user.organization_id', // = "user"."organization_id"
// Number comparisons
[Op.gt]: 6, // > 6
[Op.gte]: 6, // >= 6
[Op.lt]: 10, // < 10
[Op.lte]: 10, // <= 10
[Op.between]: [6, 10], // BETWEEN 6 AND 10
[Op.notBetween]: [11, 15], // NOT BETWEEN 11 AND 15
// Other operators
[Op.all]: sequelize.literal('SELECT 1'), // > ALL (SELECT 1)
[Op.in]: [1, 2], // IN [1, 2]
[Op.notIn]: [1, 2], // NOT IN [1, 2]
[Op.like]: '%hat', // LIKE '%hat'
[Op.notLike]: '%hat', // NOT LIKE '%hat'
[Op.startsWith]: 'hat', // LIKE 'hat%'
[Op.endsWith]: 'hat', // LIKE '%hat'
[Op.substring]: 'hat', // LIKE '%hat%'
[Op.iLike]: '%hat', // ILIKE '%hat' (case insensitive) (PG only)
[Op.notILike]: '%hat', // NOT ILIKE '%hat' (PG only)
[Op.regexp]: '^[h|a|t]', // REGEXP/~ '^[h|a|t]' (MySQL/PG only)
[Op.notRegexp]: '^[h|a|t]', // NOT REGEXP/!~ '^[h|a|t]' (MySQL/PG only)
[Op.iRegexp]: '^[h|a|t]', // ~* '^[h|a|t]' (PG only)
[Op.notIRegexp]: '^[h|a|t]', // !~* '^[h|a|t]' (PG only)
[Op.any]: [2, 3], // ANY ARRAY[2, 3]::INTEGER (PG only)
// In Postgres, Op.like/Op.iLike/Op.notLike can be combined to Op.any:
[Op.like]: { [Op.any]: ['cat', 'hat'] } // LIKE ANY ARRAY['cat', 'hat']
// There are more postgres-only range operators, see below
}
}
});
// 성이 없는 사람들의 성을 'doe'로 설정
await User.update({ lastName: "Doe" }, {
where: {
lastName: null
}
});
// 이름이 'Jane'인 모든 것들을 삭제
await User.destroy({
where: {
firstName: "Jane"
}
});
// 전부 삭제
await User.destroy({
truncate: true
});
Project.findAll({ group: 'name' });
// === 'GROUP BY name'
// 기본키가 123인 인스턴스를 찾는다.
const project = await Project.findByPk(123);
if (project === null) {
console.log('Not found!');
} else {
console.log(project instanceof Project);
// Its primary key is 123
}
const project = await Project.findOne({ where: { title: 'My Title' } });
if (project === null) {
console.log('Not found!');
} else {
console.log(project instanceof Project); // true
console.log(project.title); // 'My Title'
}