몽고디비

서가희·2021년 11월 11일
0

Node.js

목록 보기
7/15
post-thumbnail

NoSQL vs SQL

1. NoSQL

MySQL같은 SQL 데이터베이스와는 다른 유형의 데이터

  • NoSQL의 대표주자인 mongoDB(몽고디비) 사용
  • JOIN: 관계가 있는 테이블끼리 데이터를 합치는 기능(몽고디비 aggregate로 흉내 가능)
  • 빅데이터, 메시징, 세션 관리 등(비정형 데이터)에는 몽고디비 사용하면 좋음

몽고디비, 컴파스 설치하기

5. 몽고디비 연결하기

윈도의 경우 C:\에 data 폴더를 만들고 그 안에 db 폴더를 만듦
콘솔로 몽고디비가 설치된 경로(기본적으로 C:\Program Files\MongoDB\Server\4.2\bin)로 이동해 몽고디비를 실행

다른 콘솔을 하나 더 열어 mongo 명령어 입력

6. 어드민 설정하기

어드민 권한을 설정하여 디비에 비밀번호 걸기

use admin

mongod를 입력했던 콘솔을 종료한 후 mongod --auth 명령어로 접속

  • --auth는 로그인이 필요하다는 뜻
    mongo를 입력한 콘솔도 종료한 후 mongo admin –u 이름 –p 비밀번호로 접속

11. 커넥션 생성하기

컴퍼스(MongoDB Compass Community)로 접속

  • Fill in connection Fields individually 클릭

12. 커넥션 생성하기

컴퍼스(MongoDB Compass Community)로 접속

  • Authentication 을 Username/Password로 변경, 몽고디비 계정 이름과 비밀번호 입력

13. 커넥션 생성하기

접속 성공 화면

데이터베이스, 컬렉션 생성하기

1. 데이터베이스 생성하기

use 데이터베이스명으로 생성

use nodejs

show dbs로 목록 확인
db로 현재 사용중인 데이터베이스 확인

show dbs

db로 현재 사용중인 데이터베이스 확인

db

CRUD 작업하기

1. Create

  • 몽고디비는 컬럼을 정의하지 않아도 됨
  • 자유로움이 장점, 무엇이 들어올지 모른다는 단점
  • 자바스크립트의 자료형을 따름(차이점도 존재)
  • ObjectId: 몽고디비의 자료형으로 고유 아이디 역할을 함
  • save method로 저장

mongo

2. Create(관계 설정)

컬렉션 간 관계를 강요하는 제한이 없으므로 직접 ObjectId를 넣어 연결

  • 사용자의 ObjectId를 찾은 뒤 댓글 컬렉션에 넣음

3. Read

find로 모두 조회, findOne으로 하나만 조회

4. Read(조건)

두 번째 인수로 조회할 필드를 선택할 수 있음(1은 추가, 0은 제외)


첫 번째 인수로 조회 조건 입력 가능

  • $gt나 $or같은 조건 연산자 사용

5. Read(조건)

정렬은 sort 메서드로 함


limit 메서드로 조회할 다큐먼트 개수 제한

skip 메서드로 건너뛸 다큐먼트 개수 제공

6. Update

update 메서드로 쿼리

  • 첫 번째 인수로 수정 대상을, 두 번째 인수로 수정 내용을 제공
  • $set을 붙이지 않으면 다큐먼트 전체가 대체되므로 주의

7. Delete

remove 메서드로 쿼리

  • 첫 번째 인수로 삭제할 대상 조건 제공
  • 성공 시 삭제된 개수가 반환됨

몽구스 사용하기

1. 몽구스 ODM

몽고디비 작업을 쉽게 할 수 있도록 도와주는 라이브러리

  • ODM: Object Document Mapping: 객체와 다큐먼트를 매핑(1대1 짝지음)
  • 몽고디비에 없어 불편한 기능들을 몽구스가 보완
  • 테이블과 유사한 기능, JOIN 기능 추가

참고
https://github.com/zerocho/nodejs-book/tree/master/ch8/8.6/learn-mongoose

  • 프로젝트 세팅 후, 콘솔을 통해 경로로 이동한 후 package.json 설치

🔻packet.json

{
  "name": "learn-mongoose",
  "version": "0.0.1",
  "description": "몽구스를 배우자",
  "main": "app.js",
  "scripts": {
    "start": "nodemon app"
  },
  "author": "ZeroCho",
  "license": "MIT",
  "dependencies": {
    "express": "^4.17.1",
    "mongoose": "^5.9.10",
    "morgan": "^1.10.0",
    "nunjucks": "^3.2.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.3"
  }
}

npm i express morgan nunjucks mongoose
npm i -D nodemon

2. 몽고디비 연결하기

몽구스를 통해 몽고디비 연결하기

  • 인증은 admin 데이터베이스에서, 서비스는 dbName 데이터베이스에서

🔻scehmas/index.js

const mongoose = require('mongoose');

const connect = () => {
  if (process.env.NODE_ENV !== 'production') {
    mongoose.set('debug', true);
  }
  mongoose.connect('mongodb://root:nodejsbook@localhost:27017/admin', {
    dbName: 'nodejs',
    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;

3. 앱과 연결하기

app.js로 연결

  • schemas/index.js의 함수가 실행됨
  • mongoose.connect 함수가 몽고디비에 연결을 시도
  • mongoose.set은 디버깅 모드(모드를 켰을 때 콘솔에 쿼리가 찍힘)
  • 연결이 끊기면(disconnection) 다시 연결을 시도

🔻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'), '번 포트에서 대기 중');
});

4. 스키마 정의하기

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,
    unique: true,
  },
  age: {
    type: Number,
    required: true,
  },
  married: {
    type: Boolean,
    required: true,
  },
  comment: String,
  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',
  },
  comment: {
    type: String,
    required: true,
  },
  createdAt: {
    type: Date,
    default: Date.now,
  },
});

module.exports = mongoose.model('Comment', commentSchema);

5. 라우터 작성하기

프론트엔드 코드는 서버에 요청을 보내는 AJAX 요청 위주로
서버 코드는 응답을 보내는 라우터 위주로 살펴보기
🔻routes.index.js

const express = require('express');
const User = require('../schemas/user');

const router = express.Router();

router.get('/', async (req, res, next) => {
  try {
    const users = await User.find({});
    res.render('mongoose', { users });
  } catch (err) {
    console.error(err);
    next(err);
  }
});

module.exports = router;

6. 사용자 라우터

router.get, post, put, patch, delete 라우터 작성
🔻routes/users.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(user);
      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;

7.댓글 라우터

router.get, post, put, patch, delete 라우터 작성
🔻routes/comment.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;

8. 라우터 연결하기

app.js에 연결
🔻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);
});
...

9. 서버 연결하기

npm start 후 localhost:3000에 접속

  • 콘솔에 찍히는 몽고디비 쿼리 확인

    npm start

10. 서버 연결하기

사용자/댓글 등록/수정/삭제 해보기

😃출처😃
Node.js 교과서 - 기본부터 프로젝트 실습까지
https://www.inflearn.com/course/%EB%85%B8%EB%93%9C-%EA%B5%90%EA%B3%BC%EC%84%9C/dashboard

0개의 댓글