이 글은 Node.js 교과서(조현영 저)
라는 책으로 공부한 내용을 정리한 글입니다. 이 책에선 MySQL을 설명하지만 개인적으로 MariaDB 사용법에 대해 알아보고자 합니다.
MariaDB 설치 및 설정(MacOS)
Homebrew 설치
패키지 관리자인 Homebrew 설치 필요
- 설치 명령어:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
- 설치 후 Homebrew에서 관리하는 패키지의 최신버전이 있는지 확인:
brew update
MariaDB 설치
설치할 수 있는 MariaDB 패키지 목록 및 버전 확인: brew search mariadb
➜ ~ brew search mariadb # Homebrew에서 mariadb 패키지 검색
==> Formulae
mariadb mariadb-connector-odbc mariadb@10.2
mariadb-connector-c mariadb@10.1 mariadb@10.3
==> Casks
navicat-for-mariadb
MariaDB 10.3 버전 설치: brew install mariadb@10.3
➜ ~ brew install mariadb@10.3 # MariaDB 10.3 버전 설치
# (대충 설치 중 메시지...)
To enable mecab-ipadic dictionary, add to /usr/local/etc/mecabrc:
dicdir = /usr/local/lib/mecab/dic/ipadic
==> openssl@1.1
A CA file has been bootstrapped using certificates from the system
keychain. To add additional certificates, place .pem files in
/usr/local/etc/openssl@1.1/certs
and run
/usr/local/opt/openssl@1.1/bin/c_rehash
openssl@1.1 is keg-only, which means it was not symlinked into /usr/local,
because openssl/libressl is provided by macOS so don't link an incompatible version.
If you need to have openssl@1.1 first in your PATH run:
echo 'export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"' >> ~/.zshrc
For compilers to find openssl@1.1 you may need to set:
export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"
==> mariadb@10.3
A "/etc/my.cnf" from another install may interfere with a Homebrew-built
server starting up correctly.
MySQL is configured to only allow connections from localhost by default
To connect:
mysql -uroot
mariadb@10.3 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.
If you need to have mariadb@10.3 first in your PATH run:
echo 'export PATH="/usr/local/opt/mariadb@10.3/bin:$PATH"' >> ~/.zshrc
For compilers to find mariadb@10.3 you may need to set:
export LDFLAGS="-L/usr/local/opt/mariadb@10.3/lib"
export CPPFLAGS="-I/usr/local/opt/mariadb@10.3/include"
To have launchd start mariadb@10.3 now and restart at login:
brew services start mariadb@10.3
Or, if you don't want/need a background service you can just run:
/usr/local/opt/mariadb@10.3/bin/mysql.server start
MariaDB 경로(환경변수) 설정
mysql -uroot
명령어로 MariaDB 실행 시 command not found라고 나오면서 실행이 안 되면 MariaDB 경로에 대한 환경변수를 등록해야 함
- MariaDB를 설치한 후 다음과 같은 메시지가 출력됨. 이는 MariaDB 경로를 환경변수에 추가하기 위한 명령어를 실행하라는 메시지.
If you need to have mariadb@10.3 first in your PATH run:
echo 'export PATH="/usr/local/opt/mariadb@10.3/bin:$PATH"' >> ~/.zshrc
위에서 알려준 echo 'export PATH="/usr/local/opt/mariadb@10.3/bin:$PATH"' >> ~/.zshrc
명령어 실행
- 참고로 ZShell을 사용하는 경우 명령어의 끝 부분이
~/.zshrc
로 되어 있음. - 기본적으로 흔히 사용되는 Bash Shell인 경우
~/.bash_profile
이라고 나올 듯…
위의 명령어를 적용한 후 Zshell을 사용하는 경우 source ~/.zshrc
명령어 실행
- Bash Shell을 사용한다면
source ~/.bash_profile
명령어를 실행하면 될 듯…
MariaDB 실행
- MariaDB 실행:
mysql.server start
➜ ~ mysql.server start # MariaDB 실행
Starting MariaDB
.200112 14:21:16 mysqld_safe Logging to '/usr/local/var/mysql/Ing-Yeo-MacBook-Pro.local.err'.
200112 14:21:16 mysqld_safe Starting mysqld daemon with databases from /usr/local/var/mysql
SUCCESS!
- MariaDB 상태 확인:
mysql.server status
- MariaDB 재시작:
mysql.server restart
- MariaDB 중지:
mysql.server stop
MariaDB 루트 패스워드 설정
- 방법: DB Table을 변경, mysqladmin 유틸리티 사용 등
- 여기서는
SET PASSWORD
명령어를 사용- 비밀번호 설정이 안 된 MariaDB 루트 계정 로그인:
mysql -uroot
SET PASSWORD FOR 'root'@'localhost'=password('P@sSw0rd!');
명령어 실행FLUSH PRIVILEGES;
명령어 실행
- 비밀번호 설정이 안 된 MariaDB 루트 계정 로그인:
➜ ~ mysql -uroot # 패스워드 설정이 안 된 MariaDB 루트 계정 로그인
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 12
Server version: 10.3.20-MariaDB Homebrew
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> set password for 'root'@'localhost'=password('P@sSw0rd!'); # 루트 패스워드 설정
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> FLUSH PRIVILEGES; # 변경한 설정을 적용하기 위한 명령어
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> exit # MariaDB 종료
Bye
➜ ~
비밀번호 설정된 MariaDB 루트 계정 로그인: mysql -uroot -p
MySQL Workbench로 MariaDB 접속하기
MySQL Workbench를 설치 및 실행한 후 새로운 MySQL Connections를 다음과 같이 추가
- Hostname: 127.0.0.1
- Port: 3306 (MariaDB의 기본 포트)
- Username: root
- Password: 적절히 입력
Test Connection 버튼을 눌러 Successfully made the MySQL connection
메시지가 나온다면 정상
Incompatible/nonstandard server version or connection protocol detected (10.3.20).
라는 경고 메시지가 뜨긴 하지만 정상적으로 작동하긴 함.- MariaDB와 MySql Workbench 간의 호환성 경고인 듯…
데이터베이스 및 테이블 생성
데이터베이스 생성
- MariaDB에서 데이터베이스(스키마) 생성:
CREATE SCHEMA db_name;
- 생성된 데이터베이스 사용:
USE db_name;
MariaDB [(none)]> CREATE SCHEMA nodejs; # nodejs라는 이름의 데이터베이스(스키마) 생성
Query OK, 1 row affected (0.004 sec)
MariaDB [(none)]> USE nodejs; # nodejs 데이터베이스(스키마) 사용
Database changed
테이블 생성
# nodejs라는 데이터베이스 안에 users라는 테이블 생성
MariaDB [nodejs]> CREATE TABLE nodejs.users(
-> id INT NOT NULL AUTO_INCREMENT,
-> name VARCHAR(20) NOT NULL,
-> age INT UNSIGNED NOT NULL,
-> married TINYINT NOT NULL,
-> comment TEXT NULL,
-> created_at DATETIME NOT NULL DEFAULT now(),
-> PRIMARY KEY(id),
-> UNIQUE INDEX name_UNIQUE(name ASC))
-> COMMENT='사용자 정보'
-> DEFAULT CHARSET=utf8
-> ENGINE=InnoDB;
Query OK, 0 rows affected (0.032 sec)
# nodejs라는 데이터베이스 안에 comments라는 테이블 생성
MariaDB [nodejs]> CREATE TABLE nodejs.comments(
-> id INT NOT NULL AUTO_INCREMENT,
-> commenter INT NOT NULL,
-> comment VARCHAR(100) NOT NULL,
-> created_at DATETIME NOT NULL DEFAULT now(),
-> PRIMARY KEY(id),
-> INDEX commenter_idx(commenter ASC),
-> CONSTRAINT commenter
-> FOREIGN KEY(commenter)
-> REFERENCES nodejs.users(id)
-> ON DELETE CASCADE
-> ON UPDATE CASCADE)
-> COMMENT='댓글'
-> DEFAULT CHARSET=utf8
-> ENGINE=InnoDB;
Query OK, 0 rows affected (0.017 sec)
위의 쿼리문에서 사용한 자료형
INT
: 정수- 소수:
FLOAT
또는DOUBLE
- 소수:
VARCHAR(자릿수)
: 가변길이 문자열. 해당 자릿수까지 문자열을 넣을 수 있음.CHAR(자릿수)
는 반드시 자릿수만큼 문자열을 넣어야 하며 그렇지 않은 경우 부족한 자릿수만큼 스페이스가 채워짐.
TEXT
: 긴 글을 저장할 때 사용- 몇백 자 이내의 문자열은 VARCHAR를, 그 보다 길면 TEXT로 주로 처리
TINYINT
: -127 ~ 128 까지의 정수- 1 또는 0만 저장한다면 참거짓 판별을 위한 불 값(Boolean)과 같은 역할을 할 수 있음
DATETIME
: 날짜 및 시간에 대한 정보DATE
: 날짜 정보만 포함TIME
: 시간 정보만 포함
위의 쿼리문에서 자료형 뒤에 사용된 컬럼(열) 옵션
NULL
: 빈 값 허용NOT NULL
: 빈 값을 허용하지 않음
AUTO_INCREMENT
: 숫자를 저절로 상승UNSIGNED
: 숫자 자료형에만 적용되는 옵션. 음수값 무시.- 이 옵션을 적용하면 숫자 자료형의 범위가 양수로 확장됨 (예: INT의 범위는 대략 -21억 ~ 21억인 반면 UNSIGNED INT의 범위는 대략 0 ~ 42억)
- 나이처럼 음수가 나올 수 없는 컬럼에 적용
ZEROFILL
: 숫자의 자릿수가 고정되어 있을 때 비어있는 자리를 0으로 채움- 예: INT(4)인데 숫자 1을 넣었다면 0001이 됨
DEFAULT value
: 해당 컬럼에 값을 지정하지 않으면 기본값을 대신 넣어줌- 예: DEFAULT now()는 현재 시각을 기본값으로 넣을 것을 명시
PRIMARY KEY(컬럼명)
: 테이블에 저장된 값(행)을 식별하기 위한 기본키 설정UNIQUE INDEX
: 해당 값이 고유해야 하는지 결정- 예: UNIQUE INDEX name_UNIQUE(name ASC)는 인덱스의 이름을 name_UNIQUE로 하여 name 컬럼을 오름차순(ASC)으로 기억할 것임을 명시
- PRIMARY KEY나 UNIQUE INDEX는 데이터베이스가 별도로 컬럼(열)을 관리하므로 조회 시 속도가 빨라짐
- PRIMARY KEY는 자동으로 UNIQUE INDEX를 포함하므로 따로 명시하지 않음
CONSTRAINT 제약조건명 FOREIGN KEY(컬럼명) REFERENCES 참고할_컬럼명
: 외래키(다른 테이블의 기본키를 저장하는 컬럼) 지정- 위에서 실행한 쿼리문은 commenter(댓글 작성자의 ID) 컬럼에 users 테이블의 id 컬럼 값을 저장
ON UPDATE CASCADE
: 정보 수정 시 그것과 연관된 정보도 같이 수정ON DELETE CASCADE
: 정보 삭제 시 그것과 연관된 정보도 같이 삭제
위의 쿼리문에서 사용한 테이블 자체 설정
COMMENT
: 테이블 보충 설명DEFAULT CHARSET
: 문자열 기본 인코딩 설정- utf8이 아니면 한글이 입력되지 않음
ENGINE
: DB 엔진 설정- 종류: MyISAM, InnoDB 등
만들어진 테이블의 구조 확인
DESC table_name;
MariaDB [nodejs]> DESC users; # users 테이블 구조 확인
+------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | UNI | NULL | |
| age | int(10) unsigned | NO | | NULL | |
| married | tinyint(4) | NO | | NULL | |
| comment | text | YES | | NULL | |
| created_at | datetime | NO | | current_timestamp() | |
+------------+------------------+------+-----+---------------------+----------------+
6 rows in set (0.006 sec)
CRUD 작업
Create(생성)
테이블에 데이터(행)를 넣는 쿼리문: INSERT INTO table_name (column_1, column_2, ..., column_n) VALUES (value_1, value_2, ..., value_n)
MariaDB [nodejs]> INSERT INTO nodejs.users(name, age, married, comment) VALUES ('pengsu', 10, 0, '안녕요?ㅎ');
Query OK, 1 row affected (0.001 sec)
Read(조회)
SELECT 문으로 테이블 내의 데이터(행) 조회
MariaDB [nodejs]> select * from users;
+----+--------+-----+---------+---------------+---------------------+
| id | name | age | married | comment | created_at |
+----+--------+-----+---------+---------------+---------------------+
| 1 | pengsu | 10 | 0 | 안녕요?ㅎ | 2020-01-12 15:34:12 |
+----+--------+-----+---------+---------------+---------------------+
1 row in set (0.000 sec)
Update(수정)
테이블에 존재하는 데이터(행)을 수정하는 쿼리문: UPDATE table_name SET column_name=valuue WHERE condition
MariaDB [nodejs]> update nodejs.users SET comment='펭하!' WHERE id=1;
Query OK, 1 row affected (0.002 sec)
Rows matched: 1 Changed: 1 Warnings: 0
Delete(삭제)
테이블에 존재하는 데이터(행)을 삭제하는 쿼리문: DELETE FROM table_name WHERE condition
MariaDB [nodejs]> DELETE FROM users WHERE id=1;
Query OK, 1 row affected (0.001 sec)
MariaDB 연동 연습을 위한 Express 프로젝트 생성
Express로 웹 서버 구축 후 이를 MariaDB와 연동하려 함
- Express 프로젝트 자동 생성을 위한 express-generator 설치:
npm i -g express-generator
- FOLDER_NAME이라는 이름의 폴더에 Express 프로젝트 생성:
express FOLDER_NAME --view=pug
➜ Nodejs express learn-sequelize --view=pug # learn-sequelize 폴더에 Express 프로젝트 생성
# 대충 설치 과정.......
- FOLDER_NAME 폴더로 이동 후
npm i
명령어 실행
➜ Nodejs cd learn-sequelize # learn-sequelize 폴더로 이동
➜ learn-sequelize npm i # 프로젝트에 필요한 npm 패키지 설치
npm start
명령어 실행 후 웹 브라우저로 http://localhost:3000 에 제대로 접속되는지 확인
➜ learn-sequelize npm start
> learn-sequelize@0.0.0 start /Users/ingyeo/Documents/Study/Nodejs/learn-sequelize
> node ./bin/www
Node.js – MariaDB 연동: 1. 쿼리문 직접 실행
https://www.smoh.kr/202 사이트를 참고하여 코딩함
- Express 프로젝트 폴더 경로에서 MariaDB Connector 설치:
npm i mariadb
- MariaDB 접속 정보를 가진 pool 객체 및 커넥터 함수 구현
/*** models/mariaDBConn.js ***/
var mariadb = require('mariadb');
const pool = mariadb.createPool({
host: '127.0.0.1',
port: 3306,
user: 'root',
password: 'P@SsW0Rd!',
connectionLimit: 5
});
async function getUserList() {
let conn, rows;
try {
conn = await pool.getConnection();
conn.query('USE nodejs'); // 사용할 DB 명시
rows = await conn.query('SELECT * FROM users'); // 쿼리 실행
}
catch (err) { throw err; }
finally {
if (conn) conn.end();
return rows;
}
}
module.exports = { getUserList, }
/*** routes/index.js ***/
var mdbConn = require('../models/mariaDBConn');
var express = require('express');
var router = express.Router();
/* localhost:3000 주소로 접속 시 작동되는 라우터 */
router.get('/', function (req, res, next) {
mdbConn.getUserList()
.then((rows) => { res.json(rows) }) // 쿼리 결과가 JSON 형태로 출력됨
.catch((err) => { console.error(err); });
});
module.exports = router;
Node.js – MariaDB 연동: 2. 시퀄라이즈(Sequelize) 사용
시퀄라이즈(Sequelize): Node에서 MariaDB 작업을 쉽게 도와주는 라이브러리
- 자바스크립트 구문을 SQL로 변환
- SQL을 쓰지 않아도 자바스크립트만으로 MariaDB를 조작할 수 있음
설치
- Express 프로젝트 폴더 경로에서 sequelize 및 mariadb 패키지 설치:
npm i sequelize mariadb
- sequelize 커맨드 사용을 위한 sequelize 전역 설치:
npm i -g sequelize-cli
sequelize init
- 이 명령어를 실행하면 config, models, migrations, seeders 폴더가 생성됨
- sequelize-cli에 의해 models 폴더 안에 index.js 파일이 자동 생성되나 그대로 사용 시 에러가 발생하고 필요없는 코드도 있으므로 다음과 같이 수정
/*** models/index.js ***/
const path = require('path');
const Sequelize = require('sequelize');
const env = process.env.NODE_ENV || 'development';
const config = require(path.join(__dirname, '..', 'config', 'config.json'))[env];
const db = {};
const sequelize = new Sequelize(config.database, config.username, config.password, config);
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
MariaDB 연결
app.js
파일에 시퀄라이즈 연동 코드 작성
/*** app.js ***/
// ...
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var sequelize = require('./models').sequelize; // sequelize require
var app = express();
sequelize.sync(); // 서버 실행 시 MariaDB와 연동
// ...
참고로 require('./models')
는 require('./models/index.js')
와 같음. 폴더 내의 index.js 파일은 require 시 이름을 생략할 수 있음.
모델 정의
- MariaDB에서 정의한 테이블을 시퀄라이즈에서 정의
- MariaDB의 테이블은 시퀄라이즈의 모델과 대응됨
- 기본적으로 모델 이름은 단수형으로 사용
- 테이블 이름은 복수형으로 사용
시퀄라이즈 모델을 정의하는 메서드: sequelize.define()
/*** models/user.js ***/
// 이전에 MariaDB에 users 테이블과 comments 테이블을 만들었으니
// 시퀄라이즈에 User 모델과 Comment 모델 생성 및 연결
module.exports = (sequelize, DataTypes) => {
return sequelize.define(
/* 첫번째 인자: 테이블 이름 */
'user',
/* 두번째 인자: 컬럼 모델 */
{
// 시퀄라이즈는 기본적으로 id를 기본키로 연결하므로 id 컬럼은 적을 필요가 없음
name: {
type: DataTypes.STRING(20), // VARCHAR -> STRING
allowNull: false, // NOT NULL -> allowNull
unique: true, // UNIQUE -> unique
},
age: {
type: DataTypes.INTEGER.UNSIGNED, // INT -> INTEGER
allowNull: false,
},
married: {
type: DataTypes.BOOLEAN, // TINYINT -> BOOLEAN
allowNull: false,
},
comment: {
type: DataTypes.TEXT, // TEXT = TEXT
allowNull: true,
},
created_at: {
type: DataTypes.DATE, // DATETIME -> DATE
allowNull: false,
defaultValue: sequelize.literal('now()'),
},
},
/* 세번째 인자: 테이블 옵션 */
{
timestamps: false, // true 시 시퀄라이즈는 자동으로 createdAt과 updateAt 컬럼 추가
});
};
/*** models/comment.js ***/
module.exports = (sequelize, DataTypes) => {
return sequelize.define('comment', {
comment: {
type: DataTypes.STRING(100),
allowNull: false,
},
// commenter 컬럼에 대한 모델은 없음.
// 여기에 정의해도 되긴 하지만 시퀄라이즈 자체에서 관계를 따로 정의할 수 있음.
// 이것에 대해선 나중에...
created_at: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: sequelize.literal('now()'),
},
}, {
timestamps: false,
});
};
시퀄라이즈의 자료형
MariaDB의 자료형과는 조금 다름
VARCHAR
->STRING
INT
->INTEGER
TINYINT
->BOOLEAN
DATETIME
->DATE
UNSIGNED
가 적용된INT
->INTEGER.UNSIGNED
ZEROFILL
->INTEGER.UNSIGNED.ZEROFILL
시퀄라이즈 옵션
옵션도 MariaDB와 조금 다름
NOT NULL
->allowNull
UNIQUE
->unique
DEFAULT
->defaultValue
주요 테이블 옵션
timestamps
: 시퀄라이즈가 자동으로 createdAt과 updateAt 컬럼을 만들고 그 값도 자동 입력하도록 함paranoid
: 시퀄라이즈가 자동으로 deletedAt 컬럼을 만들고 그 값도 자동 입력하도록 함- 이 옵션은
timestamps
옵션이 true일 때 활성화됨 - 데이터(행)을 삭제하는 명령을 내리면 실제로 삭제하는 대신 deletedAt에 제거된 날짜를 입력함
- 이 옵션은
tableName
: 시퀄라이즈가 생성하는 테이블 이름을 직접 설정할 때 사용- 시퀄라이즈는 define() 메서드의 첫번째 인자를 복수형으로 만들어 테이블 이름으로 사용함. 이런 자동 변환을 막을 때 사용.
모델 연결
models/index.js
와 연결
/*** models/index.js ***/
const path = require('path');
const Sequelize = require('sequelize');
const env = process.env.NODE_ENV || 'development';
const config = require(path.join(__dirname, '..', 'config', 'config.json'))[env];
const db = {};
const sequelize = new Sequelize(config.database, config.username, config.password, config);
db.sequelize = sequelize;
db.Sequelize = Sequelize;
// db 객체에 User 및 Comment 모델을 담아둠
// db 객체를 require하여 User 및 Comment 모델에 접근할 수 있음.
db.User = require('./user')(sequelize, Sequelize);
db.Comment = require('./comment')(sequelize, Sequelize);
module.exports = db;
마지막으로 config 폴더 안의 config.json
파일의 development 속성을 다음과 같이 알맞게 수정
- test와 production 속성은 각각 테스트와 배포 용으로 사용되므로 나중에 사용
- development 속성에 대한 설정은 process.env.NODE_ENV가 development일 때 적용됨
- 나중에 배포할 때는 이 값을 production으로 설정
- 마찬가지로 테스트 환경에서는 이 값을 test로 설정
{
"development": {
"username": "root",
"password": "P@sSw0rd!",
"database": "nodejs",
"host": "127.0.0.1",
"dialect": "mariadb",
"operatorsAliases": false
},
// ...
}
관계 정의
1:N 관계
comments 테이블의 외래키는 commenter 행이며 이는 user 테이블의 id 행을 참조함
- 한 명의 유저는 여러 개의 댓글을 달 수 있고, 각각의 댓글에 작성자가 여러명일 수 없음
- 따라서 users 테이블과 comments 테이블은 1:N 관계
시퀄라이즈에서 1:N 관계를 표현하는 메서드: hasMany()
- 그 반대 방향을 표현하는 메서드:
belongsTo()
/*** models/index.js ***/
// ...
db.sequelize = sequelize;
db.Sequelize = Sequelize;
db.User = require('./user')(sequelize, Sequelize);
db.Comment = require('./comment')(sequelize, Sequelize);
/* user -> comment: 1 -> N */
db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id'});
/* comment -> user: N -> 1 */
db.Comment.belongsTo(db.User, { foreignKey: 'commenter', targetKey: 'id'});
// ...
1:1 관계
시퀄라이즈에서 1:1 관계를 표현하는 메서드: hasOne()
- 그 반대방향을 표현하는 메서드
belongsTo()
db.User.hasOne(db.Info, { foreignKey: 'user_id', sourceKey: 'id' }); db.Info.belongsTo(db..User, { foreignKey: 'user_id', targetKey: 'id' });
N:M 관계
하나의 글엔 여러 개의 해시태그를 가질 수 있고 하나의 해시태그는 여러 개의 글에 포함될 수 있으므로 이는 N:M 관계
시퀄라이즈에서 N:M 관계를 표현하는 메서드: belongsToMany()
// through 속성: N:M 관계 특성 상 새롭게 생성될 모델의 이름을 명시
db.Post.belongsToMany(db.Hashtag, {through: 'PostHashtag' });
db.HashTag.belongsToMany(db.Post, {through: 'PostHashtag' });
// 이렇게 생성된 모델은 Post(id, content) <-> PostHashtag(postid, hashtagid) <-> Hashtag(id, title) 관계 테이블로서 정의됩니다.
시퀄라이즈 쿼리 생성
시퀄라이즈 쿼리는 SQL문을 자바스크립트로 생성하며 프로미스를 반환
생성
/* routes에 구현 */
const { User } = require('../models');
// INSERT INTO nodejs.users(name, age, married, comment) VALUES('pengsu', 10, 0, '자기소개1');
User.create({
name: 'pengsu',
age: 10,
married: false, // MariaDB의 자료형이 아닌 시퀄라이즈 모델에 정의한 자료형을 넣어야 함
comment: '자기소개1',
});
조회
// db.User, Sequelize.Op 객체 가져오기
const { User, Sequelize: { Op } } = require('../models');
// SELECT * FROM nodejs.users;
User.findAll({});
// SELECT * FROM nodejs.users LIMIT 1;
User.findAll({});
// SELECT name, married FROM nodejs.users;
User.FindAll({
attributes: ['name', 'married'],
});
// SELECT name, age FROM nodejs.users WHERE married=1 AND age>30
User.findAll({
attributes: ['name', 'age'],
where: {
married: 1,
age: { [Op.gt]: 30 },
},
});
// SELECT id, name FROM users WHERE married=0 OR age>30;
User.findAll({
attributes: ['id', 'name'],
where: {
[Op.or]: [ { married: 0 }, { age: { [Op.gt]: 30 } } ],
},
});
// 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,
});
시퀄라이즈의 Op 연산자 종류
Op.gt
: 초과(>)Op.gte
: 이상(>=)Op.lt
: 미만(<)Op.lte
: 이하(<=)Op.ne
: 같지 않음(!=)Op.or
: 또는(|)Op.in
: 포함Op.notIn
: 미포함
수정
const { User } = require('../models');
// UPDATE nodejs.users SET comment='바꿀 내용' WHERE id=2;
User.update({
comment: '바꿀 내용',
}, {
where: { id: 2 },
});
삭제
const { User } = require('../models');
// DELETE FROM nodejs.users WHERE id=2;
User.destroy({
where: { id: 2 },
});
시퀄라이즈 쿼리 실행
단순히 DB 정보를 json 형태로 보여주는 코드만 간단하게 설명(프론트엔드는 구현하지 않음)
/*** routes/index.js ***/
var express = require('express');
var User = require('../models').User;
var router = express.Router();
router.get('/', function (req, res, next) {
User.findAll()
.then((users) => {
res.json(users);
})
.catch((err) => {
console.error(err);
next(err);
});
});
module.exports = router;
/*** routes/users.js ***/
var express = require('express');
var User = require('../models').User;
var router = express.Router();
router.get('/', function(req, res, next) {
User.findAll()
.then((users) => {
res.json(users);
})
.catch((err) => {
console.error(err);
next(err);
});
});
router.post('/', function(req, res, next) {
User.create({
name: req.body.name, // req.body는 프론트엔드 측에서 받아온 정보
age: req.body.age,
married: req.body.married,
})
.then((result) => {
console.log(result);
res.status(201).json(result); // http status 201: Created
})
.catch((err) => {
console.error(err);
next(err);
});
});
module.exports = router;
/*** routes/comments.js ***/
var express = require('express');
var { User, Comment } = require('../models');
var router = express.Router();
router.get('/:id', function(req, res, next) {
Comment.findAll({
include: {
model: User,
where: { id: req.params.id },
},
})
.then((comments) => {
console.log(comments);
res.json(comments);
})
.catch((err) => {
console.error(err);
next(err);
});
});
router.post('/', function(req, res, next) {
Comment.create({
commenter: req.body.id,
comment: req.body.comment,
})
.then((result) => {
console.log(result);
res.status(201).json(result);
})
.catch((err) => {
console.error(err);
next(err);
});
});
router.patch('/:id', function(req, res, next) {
Comment.update({ comment: req.body.comment }, { where: { id: req.params.id } })
.then((result) => {
res.json(result);
})
.catch((err) => {
console.error(err);
next(err);
});
});
router.delete('/:id', function(req, res, next) {
Comment.destroy({ where: { id: req.params.id } })
.then((result) => {
res.json(result);
})
.catch((err) => {
console.error(err);
next(err);
});
});
module.exports = router;