작은 회사에 가면, 사실상 풀스택이다. 백을 뽑아도 프론트를 어느정도 해야하고, 거꾸로일 수도 있다. 반대로 큰 회사에 가면 분업을 하여 DB관련 회사가 아니라면 볼 일이 없을 수도 있다. 그러나 그게 아니더라도 "소양" 으로서의 DB 정도는 할 줄 알아야 한다.
SELECT
, WildCard
등으로 조회하는 게 가능하면 된다.
그려면, "두 번째로" 높은 점수는 어떻게 가지고 올 수 있을까?
Select max(scores)
from exams where
scores < (select max(scores) from exams);
일단은 가장 무난한 방법인, "최댓값보다 적은 값 중 가장 큰 값 가져오기" 방법이다. Nestsed Query 를 사용한 방법이다.
그리고 저 쿼리문을 통으로 ALIASES
를 통해 사용할 수도 있다
(Select max(scores)
from exams where
scores < (select max(scores) from exams)) AS getSecond;
왜냐면 저 쿼리 자체가 table 을 만들어서 주는 쿼리이기 때문이다. 테이블에 대한 aliases 문법이 적용가능한 이유.
Depth 가 한 단계, 두 단계인 경우는 이런 식으로 할 줄 알아야 하지만, 더 깊은 경우는 ORM 을 사용하거나, framework 를 사용한다. 굳이 Raw Query 문법에 그렇게 엄청난 depth 를 사용할 필요는 없다.
직접 DB를 설계하고, Schema Best Practice 를 많이 찾아보면서 공부하면 된다. 각 field 마다 어떤 자료형을 사용하는지도 확인해야 한다. indexing 에 대한 유-불리가 있는지를 고려해야 하기 때문이다. 그렇게 하면 나아질 수 있다.
큰 스케일을 만들고 싶으면, High Scalability 라는 사이트를 활용해서 공부하면 된다. 물론, 지금은 열심히 공부하고 수준을 쌓고 다시 보면 된다. 아직은 어렵다
1:1, 1:N, N:M 의 관계. N:M 의 경우는 중간에 JOIN Table 을 넣어준 뒤 1:N 구조를 두 개를 만들어 주는 식으로 치환한다.
뭔가 조금... 연습은 해 봐야 할 것 같지만, 솔직히 많이 어렵지 않다면 할 수 있을 거 같다는 생각에 "할 수 있으나, 자신이 없다" 라는 응답을 했다.
SQL은 하나의 표준이다. 그러나 그 표준을 만드는데 "공통사항" 과 "권고사항" 이 존재하기 때문에, "공통사항" 은 표준대로 무조건 지켜야 하겠지만, "권고사항" 은 구현하는 사람들마다 조금씩 다르기 때문에 DBMS 마다 차이가 있다는 점을 알아두어야 한다.
간단히 말해, 다른 DBMS에서는 되는데, MySQL 같에서는 안 될수도 있고, 그 역의 상황이 발생할 수도 있다는 점이다. 그래서 당황할 필요가 없다
1970년도에 IBM 엔지니어(2명...!) 들이 만든 SEQUEL(structured english query language)이 SQL의 시작이다. 그러나 그 SEQUEL 은 특허가 있었기 때문에 relational software, 현재의 ORACLE 은 SQL 이라는 상표로 그것을 만든다. 그러다가, 그 SQL이 ISO 에 의해서 산업표준이 된다. 그리고 그렇게 상황을 거쳐서
아래와 같은 상황들로 발전하게 된다.
File System 을 사용했다. 즉, file 에 직접 read/write 를 했다는 점이다. DB도 물론 FS 를 거치진 않을 수 없다. 그러나, FS보다 더욱 편하게 작업하기 위해 이런저런 공정들을 거쳐주고, 더욱 추상화를 시켰다는 차이점이 있다.
File System 의 단점은 이런것들이 있다.
Data redundancy
Data inconsistency
Difficult data access
Security problems (unauthorized access)
Difficult concurrent access
Typically, in a file-based system, when an application opens a file, that file is locked
그리고 세상(의 정보)를 entity - entity 와의 "관계"를 통해 보는 그 관점이 잘 먹혀서 지금도 SQL 이 잘 사용되고 있다.
지금은 또 새로운 패러다임이 등장했다. 꼭 Structured 가 구조가 아닌, UnStructured 스타일도 나오고, 그 중간점 쯤 되는 Semi-Structured 라는 스타일도 나왔다. 스케일이 커지니까 꼭 Schema 를 통해서 관리해서는 안 된다. 이런 것들을 NoSQL
이라고 한다. NoSQL 의 대표주자는 점유율 기준으로는 MongoDB
.
그런데 위에서 말 한대로 서비스를 크게 하는 회사들은 DB를 한 종류에만 쓰지 않는다. 특정 부분에 강점을 보이는 DB들이 존재하기 때문에 취사선택을 한다.
No-SQL
key-value stores: Redis, Amazon Dynamo DB
column stores: HBase, Cassandra
document stores: Mongo DB
graph databases: Neo4J
search engines: Solr, ElasticSearch, SplunkMERN
Consensus (전파) 가 Strict 한 대신 빠른 MySQL, Consensus 가 Strict 하지 않은 대신 약간은 딜레이가 있는 NoSQL. 전자는 무조건 DB상의 갱신이 발생하면 그 갱신결과를 빠르게 전파해야하는 은행, 항공기좌석예약 시스템 등에서 사용할 것이고, 후자는 그렇게 빠르게 전파할 필요는 없는 다른 서비스에서
Ec2, s3, DB(dynamoDB, aurora, sql)cloudfrontauto-scaling), lambda, Docker (ecs)
별의 별 게 다 있다... 이 정도만 쓸 줄 알아도 정말! 정말! 도움된다
그리고 프로젝트 할 때 MongoDB 도 도전해보시길
스키마를 효율적으로 구성한다 라고 정의할 수 있는 것들이 있을까요? 예를들면 동일한 데이터(text)는 1회만 존재해야한다... 등등
있다면 찾아볼 수 있는 키워드들은 어떻게 될까요
정규화를 찾아봐라
코드의 구조를 하나에 통으로 쓰는 게 아니라, model - view - controller 로 기능을 분할해 놓는 행위를(Design Pattern) 의미한다. 어떻게 보면 옷장에 속옷 / 겉옷 등을 마구잡이로 박아놓는 게 아니라, 속옷은 속옷을 놓는 곳에, 겉옷은 겉옷을 놓는 곳에 정리정돈해서, 꺼내기가 쉽게끔 하는 행위와 비슷하다고 할 수 있다.
이런 MVC 컨셉은 Ruby, Express, Angular, Flask 등에서 많이 사용한다.
Data를 가지고 있거나, DB와 연결이 되어있어서 DB로부터 데이터를 참조하는 형식이다.
유저가 보는 화면을 그려내는 부분이다. 웹의 경우는 HTML/CSS 로 작성된 작업물들이 속한다. 그저 그려낼 뿐이다.
view 에서 일어나는 action 을 비롯한 Input value 를 받아 가공하고, model 로 넘겨준다. 거꾸로 model 에서 view 에 data 를 데이터를 반환해주는 경우, controller 가 이해하기 쉽게 가공을 거친 뒤 view section 으로 넘겨준다.
다 기능에 따라 나누어진, 구조화된 덕분에 가능한 일
Object-Relational-Mapping
의 약자, Realtional Database 에 접근할 때, JS 의 객체를 사용할 때처럼 접근할 수 있게 해주는 역할을 한다.
우리가 Obejct 를 생성하고 수정하고 접근하는 과정은 RDB 에서 table, column 등에 치환해서 생각해 볼 수 있으나, 둘의 문법은 다르다. 그래서, ORM이라는 것이 등장했다. ORM 은 JS 코드에 익숙하고 RDBMS 의 코드에는 익숙하지 않은 사람들이 JS 의 OOP 와 같이 RDBMS 를 사용할 수 있게끔 하는, 일종의 "번역기" 같은 역할을 한다.
ORM 의 일종으로, 다양한 RDBMS 를 지원한다. (Postgres, MySQL, MariaDB 등등). 그래서 SQL 이라는 표준에 각자 조금씩 다르게 구현한 RDBMS 의 미묘한 차이를 ORM 을 사용한다면 크게 신경써주지 않아도 된다. 물론 ORM 이 존재하더라도, JOIN
과도 같은 "개념" 은 우리가 이해해야 적절하게 사용할 수 있기 때문에 SQL 문법에 어느정도 익숙해져야 한다.
자세한 사용방법은 Sequelize 의 문서를 참조하면서 알아보자.
PRIMARY KEY
로 이용하는 id
, 생성일시나 변경일시를 작성하는 created_at
, updated_at
등을 기본적으로 지원한다 → 그렇기에 별도로 ORM 코드에 명시해줄 필요는 없다.Promise
기반이기 때문에, .then
을 사용해 체이닝을 할 수 있다. → 비동기이기 때문에 async 도 가능할지 확인해보고 싶다.사전적 의미는 "연관을 짓는 행위". SQL 의 JOIN
과 관련이 있다. 실무에서 JOIN 을 흔하게 사용하기 때문에 ORM 을 통해 table JOIN 을 해 보자! (공식문서의 association 항목에서 참조 가능)
은행 업무를 떠올려보자. 그 중에서 송금해야 되는 내용을 query 로 날린다고 생각해보자. 그 송금 query 는 통장에서의 조회 / 통장에서의 출금 / 다른 통장으로서의 입금 이라는 과정이 섞였을 것이다. 그런데, 내 통장에서의 조회와 출금은 잘 되었는데 DB에 오류가 생겨서 다른 통장으로 입금이 되지 않았다면 굉장히 곤란한 상황일 것이다. 그 때 우리는 rollback
을 하게 되고, 다시 시도해서 성공했을 때 성공하면 commit
을 한다
→ ...라고만 하셨는데, 뭔지는 공식문서를 보고 확실히 정리하자.
위에서 알게 된 Sequelize
라는 ORM 을 이용하여 테이블을 만들고, request 와 그에 수반되는 SQL query 또한 ORM 으로 디자인해보는 스프린트이다. 거기에, MVC 패턴으로 기능별로 코드를 분할해 정리한다.
공식 홈페이지를 기반으로 ORM 을 설치한다.
sequelize migration 또한 같이 설치한다.
Just like you use version control systems such as Git to manage changes in your source code, you can use migrations to keep track of changes to the database. With migrations you can transfer your existing database into another state and vice versa: Those state transitions are saved in migration files, which describe how to get to the new state and how to revert the changes in order to get back to the old state.
migration 단락에서 소개하는 부분을 읽어봤는데, 우리가 git 을 통해 버전 관리를 하는 것처럼 DB 에서도 버전의 변화 등을 기록하는 걸 migration 을 통해 할 수 있다고 한다.
init
을 이용해서 migration 관련 세팅을 한 큐에 진행할 수 있다. 마치 npx react create-react-app
과도 같은 느낌. bootstraping 이란 단어도 처음 봐서 검색해봤는데, 위키에서 그 의미를 잘 설명해줘서 밑에 적어보았다. 아, bootstrapping 은 해당 명령어를 터미널에 입력하면 할 수 있다.
npx sequelize-cli init
그렇게 하면 config
, migrations
, models
, seeders
라는 폴더들이 만들어진다.
각 폴더들의 역할을 적어보자면, 이러하다
confing
: "CLI 에게 어떻게 DB와 연결하라" 라는 config 파일들을 저장하는 폴더
models
: 내 project 의 모든 model 들을 저장하는 폴더
migrations
: 모든 migration 파일들을 저장하는 폴더
seeders
: 모든 seed 파일들을 저장하는 폴더
{
"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"
}
}
config 폴더의 config 파일을 여니 이런 JSON 이 있었다. 기본적으로 MySQL 을 사용하는데, 다른 DBMS 를 사용한다면 저 dialect
에다가 입력하라고 한다. development
, test
, production
의 key 는 model/index.js
에서 process.env.NODE_ENV
와 matching 하는 데 사용한다고 한다. 만약 NODE_ENV
라는 환경변수가 딱히 지정되어있지 않으면, development
를 기준으로 시작한다고 한다. 포트번호는 각 RDBMS 의 기본 포트넘버를 사용한다고 하는데, 별도로 지정해 주고 싶으면 port
라는 key 를 만들고, 포트번호를 그 안에 value 로 적어주면 된다고 한다.
"development": {
"username": "root",
"password": null,
"database": "database_development",
"host": "127.0.0.1",
"dialect": "mysql",
"port" : 8080
}
이런 식으로
위의 과정으로 Migration 을 할 수 있는 과정도 다 끝났다. migration 또한 간단한 command 로 실행할 수 있다. 이번에는 model:generate
명령어를 사용할 건데, 이 명령에는 두 가지 Option 을 필요로 한다.
name
: 모델의 이름attribute
: model attribute 의 목록예시로, User
라는 model 을 만들어보자
npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string
이렇게 해서 우리는 User
라는 이름의 model file 을 users
폴더에 만들어 넣었다. 동시에 20200907071556-create-user.js
라는 이름의 migration file 도 migrations
이라는 폴더에 집어넣었다.
이제 DB에 직접 어떤 값을 추가해보자. 그러려면 먼저 db:migrate
라는 명령어를 통해서 migration 을 해 주어야 한다.
npx sequelize-cli db:migrate
그렇지만 해당 명령어를 통해 실행해봤더니, Please install mysql2 package manually
라는 에러메시지와 함께 실행이 되지 않았다. 그래서 구글링을 해 본 결과, stackoverflow 에서 나오기를, 그냥 설치하란다. 설치하기 전, package.json
파일을 확인해 봤는데 mysql2 가 이미 dependencies
에 있었다.
생각해보니 해당 스프린트를 시작할 때 npm install
을 하지 않았다는 사실을 뒤늦게 알게 되었다....
ERROR: Please install mysql2 package manually
그래서 설치해보았다. 이번에는 내가 sql 계정의 비밀번호를 걸어놓고 config 파일은 바꾸지 않아서 잘 되지 않았다. 그래서 dotenv
를 활용해 환경변수를 잡기로 했다. 물론 exports
같은 것도 있지만, 내가 지금 사용하고 있는 터미널이 죽으면 또 해 줘야 하기 때문에 이걸 사용해서... 인데 생각해보니 그냥 config.json
안에 비밀번호를 입력하고 그걸 통째로 .gitignore
에 추가하면 되어서 그냥 npm install —save dotenv
정도만 해 놨다. 이번에도 시도해보았지만, Unknown Database
가 나오길래 구글링 해 봤더니, sequelize db:create
를 입력해서 해결하면 된다고 한다.
unhandled rejection sequelizeconnectionerror: unknown database
여튼, 그렇게 해서 해당 명령어를 실행할 수 있었고, migration 을 위해서는 npx sequelize-cli db:migrate
를 활용하면 된다는 걸 알았다. migration 을 되돌릭 위해서는 npx sequelize-cli db:migrate:undo
를 실행해 주면 된다. 특정 시점으로 migration 을 하고싶다면 npx sequelize-cli db:migrate:undo:all --to XXXXXXXXXXXXXX-create-posts.js
와 같이 migration file 을--to
라는 option 으로 넣어주면 된다.
seeder 를 통해 우리가 만든 모든 migration data 를 관리할 수 있다. seed 파일은 데이터에서의 변화들인데, 이걸 통해서 sample data 혹은 test data 등으로 만들 수 있다. npx sequelize-cli seed:generate --name demo-user
라는 명령어를 통해서 demo-user
라는 이름의 seed 를 만들어보자. 이렇게 하면 seeders 라는 폴더가 생기고, XXXXXXXXXXXXXX-demo-user.js
라는 우리가 아까 지정해 준 demo-user 라는 이름을 달아놓은 seed 가 생긴다. 그리고 그 파일에 들어가서, 공식문서에서 나온대로 수정을 한 번 해보자.
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.bulkInsert('Users', [{
firstName: 'John',
lastName: 'Doe',
email: 'example@example.com',
createdAt: new Date(),
updatedAt: new Date()
}]);
},
down: (queryInterface, Sequelize) => {
return queryInterface.bulkDelete('Users', null, {});
}
};
npx sequelize-cli db:seed:all
라는 명령어를 통해 seeder file 을 실행할 수 있다.
라는 과정들을 해 봤는데, 솔직히 조금 어렵다. 해 보면서 알아가야 할 듯 하다. 대략 migration 이라는 게 무엇인지, 그리고 migration 을 통해 어떤 걸 할 수 있는지를 알 수 있게 되었다. NODE_ENV 라는 환경변수에 맞추어 구동되기 떄문에 export NODE_ENV="production"
등으로 값을 할당해주면 그 값에 맞추어 DB의 작업환경이 바뀌고(어떻게 보면 git 의 branch
같다), 그리고 DB가 없다면 db:create
로 만들어주고, model:generate
를 통해 초기 model 을 생성해주고, 그렇게 버전관리를 하라는 거 같다. 버전관리는 잘 아직 어떻게 써야할지 와닿지가 않아서 진짜 해보면서 알아가야 할 거 같다는 생각이 든다.
process.env.NODE_ENV
를 따라가기 때문에, export NODE_ENV="test"
등으로 환경변수를 생성(혹은, 재할당)하여 바꾸어주면 된다. .gitignore
에 등록되어있는데, 설정파일을 git 의 관리를 받게 하는 대신, 환경변수를 사용하게 만들 수 있는가? : "json using .env" 이라는 키워드로 구를링을 해 보니 누가 방법을 적어놓았는데, 쉬워보이진 않는다. 그리고 optional 이기 때문에 요구하는 spec 에 맞춰 테스트를 통과시키는 게 우선일 듯 하다(시간은 한정되어있으니까) 그래서 나중에 해 보려고 한다. Injecting Environment Variables into JSON Files
cli 를 통해 모델을 만들기... 는 위에서 한 것대로 하면 될 듯 하다. 모델의 이름은 url, 모델의 요구사항은 url, title, visits. 위에서 만든 User.js
라는 파일을 수정하였다. migration 파일도 sequelize-cli command 를 통해 처음에 파일들을 수정하였다. 추가로 필요한 migration 이 있는 경우, migration skeleton 및 sequelizer query 양식에 맞추어 작성해봐야겠다.
Sequelize.STRING
과 Sequelize.INTEGER
의 형태로 정의해야 한다. dialects
라는 것으로 지원하기 때문에, MySQL 에다가만 맞출 수는 없으니까(추측)오늘은 뭔가 공식문서를 읽는데 시간을 참 많이 할애한 거 같다. 테스트 케이스 큰 것 두 개 중에서 한 개를 겨우 끝낼 수 있었다. 내일은 이제 이렇게 물린 DB 와 함께 MVC 패턴대로 url shortner 를 구현해보아야 겠다. 오늘의 공부는 여기서 마무리...
세상의 여러가지 모습들을 프로그래밍 개념으로 치환해서 생각하면 좋다. DB도 마찬가지로 그렇게 생각해보자. 식당에 간다면 손님과 메뉴를 테이블로 만든다면, Schema 를 어떻게 만들 수 있을까? 등등.
민철 엔지니어님께서 추천해 준 블로그의 포스팅, "백엔드 개발자를 꿈꾸는 학생개발자에게"
In computer technology the term (usually shortened to booting) usually refers to the process of loading the basic software.
컴퓨터 과학에서의 해당 의미는 기초적인 software 를 로딩하는 과정을 의미한다고 한다. 즉, 작업환경 설치.