반응형
# 몽고디비
1. NoSQL
- MySQL 같은 SQL 데이터베이스와는 다른 유형의 데이터
- NoSQL의 대표주자인 mongoDB (몽고디비) 사용.
SQL 과 NoSQL 비교 | |
SQL (MySQL) | NoSQL (몽고디비) |
규칙에 맞는 데이터 입력 | 자유로운 데이터 입력 |
테이블 간 JOIN 지원 | 컬렉션 간 JOIN 미지원 |
안정성, 일관성 | 확장성, 가용성 |
용어 (테이블, 로우, 컬럼) | 용어 (컬렉션, 다큐먼트, 필드) |
- JOIN : 관계가 있는 테이블끼리 데이터를 합치는 기능 (몽고디비 aggregate로 흉내 가능)
- 빅데이터, 메시징, 세션 관리 등 (비정형 데이터)에는 몽고디비 사용하면 좋음.
2. 몽고디비 설치
### 윈도의 경우.
- community 버전 다운로드하여 설치 진행, 설치 시 complete 클릭 후 Install MongD as a Service 체크 해제 이후에 Install MongoDB Compass는 체크하여 설치 진행.
3. 몽고디비 연결
- 윈도의 경우 C:\에 data 폴더를 만들고 그 안에 db 폴더 생성.
- 콘솔로 몽고디비가 설치된 경로(기본적으로 C:\Program Files\MongoDB\Server\5.0\bin)로 이동하여 몽고디비를 실행. 그리고 콘솔에 아래와 같이 이력하여 실행
# 콘솔
mongod
- mongd로 실행 후 그대로 놔둬야 몽고디비 서버가 돌아감. (만약 실행해둔걸 끄게되면 몽고디비 꺼짐)
- mongd가 실행된 상태에서 mongo.exe 실행 시 몽고디비 사용 가능.
4. 어드민 설정
- 어드민 권한을 설정하여 디비에 비밀번호 걸기
# 콘솔
use admin
db.createUser({ user: '이름'. pwd: '비밀번호', roles: ['root']});
- mongod를 입력했던 콘솔을 종료한 후 mongod --auth 명령어로 접속. (--auth는 로그인이 필요하다는 의미.)
- mongo를 입력한 콘솔도 종료한 후 mongo admin -u 이름 -p 비밀번호로 접속.
5. 커넥션 생성하기
- 컴퍼스 (MongDB Compass Community)로 접속 (mongod 실행된 상태에서 진행)
- Fill in connection fields individually 클릭 후 아래와 같이 입력 후 connect 진행
- 아래는 접속 성공 화면 (기본적으로 admin / config / local 존재)
6. 데이터 베이스 생성
### 터미널 이용 시.
- use 데이터베이스명으로 생성
# 콘솔
use nodejs // nodejs 이름의 데이터베이스 생성.
- show dbs로 목록 확인.
# 콘솔
show dbs
출력 예
admin 0.000GB
config 0.000GB
local 0.000GB
=> 방금 생성한 nodejs는 보이지 않음. (데이터 넣기 전까지는 보이지 않음)
- db로 현재 사용중인 데이터베이스 확인 가능.
# 콘솔
db
출력 예
nodejs
### MongoDB Compass 이용 시.
- CREATE DATABASE 클릭하여 생성
7. 컬렉션 생성 (=SQL에서의 테이블)
- 따로 생성할 필요는 없음.
- 다큐먼트(=로우)를 넣는 순간 컬렉션도 자동 생성된다.
- 직접 생성하는 명령어도 있다. (아래참고)
# 콘솔
db.createCollection('users')
{ "ok" : 1 }
db.createCollection('comments')
{ "ok" : 1 }
- show collections로 현재 컬렉션 확인 가능.
# 콘솔
show collections
출력 예
comments
users
- 컬렉션 생성 후 MongoDB Compass에서 새로고침 클릭 시 생긴 걸 확인 가능.
8. 몽고디비 CRUD 작업
### Create
- 몽고디비는 컬럼을 정의하지 않아도 된다.
- 자유로움이 장점, 무엇이 들어올지 모른다는 단점 (몽고디비는 오타에 취약하므로 필드명에 주의.)
- 자바스크립트의 자료형을 따른다. (차이점도 존재)
- ObjectId : 몽고 디비의 자료형으로 고유 아이디 역할. ( _id : ObjectId(" ") )
- save method로 저장
# 콘솔
use nodejs
db.users.save({ name: 'zero', age: 28, married: false, comment: 'hello hi.', createAt: new Date() });
db.users.save({ name: 'mero', age: 32, married: true, comment: 'what hi hello.', createAt: new Date() });
- MongoDB Compass 로 생성할 경우 : users 컬렉션 클릭 후 ADD DATA 클릭 > Insert Document 클릭하여 json 형식에 맞게 작성 or 한줄씩 추가(VIEW 옆에 { } or 목록모양 클릭)하여 생성.
### Create (관계 설정)
- 컬렉션 간 관계를 강요하는 제한이 없으므로 직접 ObjectId를 넣어 연결.
- 사용자의 ObjectId를 찾은 뒤 댓글 컬렉션에 넣음.
# 콘솔
db.users.find({ name : 'zero' }, { _id : 1 })
=>
첫 번째 객체가 find 하는 조건. ({ name : 'zero' })
두 번째 객체는 어떤 필드를 보여줄지. ({ _id : 1 }) // 1 : 보여줌, 0 : 숨김
- users에서 댓글 작성자의 ObjectId를 comments에서 commenter에 넣어주면 유저가 연결되는 것임. (단, 몽고디비가 commenter에 대해 존재하는지 여부 등을 검사해 주지 않음. 그래서 오타에 주의해야 함)
### Read
- find로 조회, findOne으로 하나만 조회
# 콘솔
db.users.find({}); // users 컬렉션 전체 조회.
db.comments.find({}); // comments 컬렉션 전체 조회.
### Read (조건)
- 두 번째 인수로 조회할 필드를 선택할 수 있다. (1은 추가 / 0은 제외) ( _id는 기본적으로 1임)
# 콘솔
db.users.find({ _id: 0, name: 1, married: 1 });
- 첫 번째 인수로 조회 조건을 입력할 수 있다. ($gt 나 $or 같은 조건 연산자 사용)
# 콘솔
db.users.find({ $or: [{ age: { $gt: 30 }, { married: false }] }, { _id: 0, name: 1, age: 1 });
- 정렬은 sort 메서드로 함. (1 : 오름차순 / -1 : 내림차순)
# 콘솔
db.users.find({}, { _id: 0, name: 1, age: 1}).sort({ age: -1 });
- limit 메서드로 조회할 다큐먼트 개수 제한
# 콘솔
db.users.find({}, { _id: 0, name: 1, age: 1 }).sort({ age: -1 }).limit(1);
- skip 메서드로 건너뛸 다큐먼트 개수 제공
# 콘솔
db.users.find({}, { _id: 0, name: 1, age: 1 }).sort({ age: -1 }).limit(1).skip(1);
### Update
- update 메서드로 쿼리.
- 첫 번째 인수로 수정 대상을, 두 번째 인수로 수정 내용을 제공
- $set을 붙이지 않으면 다큐먼트 '전체'가 대체되므로 주의
# 콘솔
db.users.update({ name: 'nero' }, { $set: { comment: '안녕하세요. 해당 필드 수정' } });
- 결과로 수정된 개수가 나옴.
### Delete
- remove 메서드로 쿼리.
- 첫 번째 인수로 삭제할 대상 조건 제공
# 콘솔
db.users.remove({ name: 'nero' });
- 성공 시 삭제된 개수가 반환 됨.
9. 몽구스 ODM
- 몽고디비 작업을 쉽게 할 수 있도록 도와주는 라이브러리. (몽고디비 드라이버도 내장되어 있음)
- ODM : Object Document Mapping로 객체와 도큐먼트를 매핑(1대 1 짝지음)
- 몽고디비에 없어 불편한 기능들을 몽구스가 보완.
- 테이블과 유사한 기능, JOIN 기능 추가.
- $set 등 빼먹는 것 방지, 쿼리빌더(쿼리를 쉽게 만들 수 있게 해주는 기능) 기능 제공.
- 몽구스 예제 참고 : https://github.com/zerocho/nodejs-book/tree/master/ch8/8.6/learn-mongoose
- 위 예제의 경우 프로젝트 세팅 후 콘솔을 통해 경로로 이동한 후 package.json 설치
# 콘솔
npm i express morgan nunjucks mongoose
npm i -D nodemon
- /schemas/index.js
const mongoose = require('mongoose');
const connect = () => {
if (process.env.NODE_ENV !== 'production') {
mongoose.set('debug', true); // 개발 시 debug 모드 true.(쿼리가 콘솔에 보이도록 해줌)
}
// mongodb://설정한 관리자아이디:비밀번호@localhost:27017/admin
mongoose.connect('mongodb://root:nodejsbook@localhost:27017/admin', { // 로그인을 위한 db
dbName: 'nodejs', // 실제로 데이터 저장할 db명
useNewUrlParser: true,
useCreateIndex: true,
}, (error) => {
if (error) {
console.log('몽고디비 연결 에러', error);
} else {
console.log('몽고디비 연결 성공');
}
});
};
// 에러 기록하는 이벤트 리스너.
mongoose.connection.on('error', (error) => {
console.error('몽고디비 연결 에러', error);
});
// 연결 끊겼을 때 연결 재시도 코드.
mongoose.connection.on('disconnected', () => {
console.error('몽고디비 연결이 끊겼습니다. 연결을 재시도합니다.');
connect();
});
module.exports = connect;
- app.js
const express = require('express');
const path = require('path');
const morgan = require('morgan');
const nunjucks = require('nunjucks');
const connect = require('./schemas');
const indexRouter = require('./routes/index');
const usersRouter = require('./routes/users');
const commentsRouter = require('./routes/comments');
const app = express();
app.set('port', process.env.PORT || 3002);
app.set('view engine', 'html');
nunjucks.configure('views', {
express: app,
watch: true,
});
connect();
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'), '번 포트에서 대기 중');
});
10. 몽구스 스키마 사용 (학습중)
### 스키마 정의하기
- schemas 폴더 안에 작성. MySQL의 테이블처럼 정해진 데이터만 들어갈 수 있게 강제함
- type은 자료형, require는 필수 여부 default는 기본값, unique는 고유 여부.
- schemas/user.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
const userSchema = new Schema({
name : {
type: String,
required: true, // required: 필수여부.
unique: true,
},
age : {
type: Number,
required: true,
},
married: {
type: Boolean,
required: true,
},
comment: String, // 이 경우 required는 false. (필수값 x)
createdAt: {
type: Date,
default: Date.now, // 현재시간
},
});
module.exports = mongoose.model('User', userSchema);
- schemas/comment.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
const { Types: { ObjectId } } = Schema;
const commentSchema = new Schema({
commenter: {
type: ObjectId,
required: true,
ref: 'User', // 관계 설정 : user를 적음으로써 user 스키라마의 ObjectId를 의미.
},
comment: {
type: String,
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model('Comment', commentSchema);
### 라우터 작성하기
- 프론트엔드 코드는 서버에 요청을 보내는 AJAX 요청 위주로, 서버 코드는 응답을 보내는 라우터 위주로 살펴보기.
### 사용자 라우터
- router.get, post, put, patch, delete 라우터 작성.
- routes/uses.js
const express = require('express');
const User = require('../schemas/user');
const Comment = require('../schemas/comment');
const router = express.Router();
router.route('/')
.get(async (req, res, next) => {
try {
const users = await User.find({});
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(users);
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.find({ commenter: req.params.id })
.populate('commenter');
console.log(comments);
res.json(comments);
} catch (err) {
console.error(err);
next(err);
}
});
module.exports = router;
- 몽구스의 populate는 자바스크립트로 하는 거라서 속도가 느리다.
### 댓글 라우터
- router.get, post, put, patch, delete 라우터 작성.
- routes/comments.js
const express = require('express');
const Comment = require('../schemas/comment');
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);
const result = await Comment.populate(comment, { path: 'commenter' });
res.status(201).json(result);
} catch (err) {
console.error(err);
next(err):
}
});
router.route('/:id')
.patch(async (req, res, next) => {
try {
const result = await Comment.update({
_id: req.params.id,
}, {
comment: req.body.comment,
});
res.json(result);
} catch (err) {
console.error(err);
next(err);
}
})
.delete(async (req, res, next) => {
try {
const result = await Comment.remove({ _id: req.params.id });
res.json(result);
} catch (err) {
console.error(err);
next(err);
}
});
module.exports = router;
### 라우터 연결하기
- app.js에 연결
- app.js
const connect = require('./schemas');
const indexRouter = require('./routes');
const usersRouter = require('./routes/users');
const commentsRouter = require('./routes/comments');
const app = express();
...
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} 라우터가 없습니다.`);
});
...
반응형
'인프런 강의 학습 > Node.js 교과서' 카테고리의 다른 글
Node.js학습_MySQL (0) | 2021.10.17 |
---|---|
Node.js학습_SNS서비스 만들기(익스프레스 이용) (0) | 2021.10.17 |
Node.js 학습_익스프레스 웹 서버 만들기 (0) | 2021.10.07 |
Node.js 학습_npm(패키지 매니저) (0) | 2021.10.05 |
Node.js 학습_http 모듈로 서버 만들기 (0) | 2021.10.04 |