MongoDB, ODM & Mongoose

류연찬·2023년 5월 15일
0

GraphQL

목록 보기
6/17

MongoDB

MongoDB문서지향(Document-Oriented) 저장소를 제공하는 NoSQL 데이터베이스 시스템입니다.

MongoDB 특징

MongoDB에서는 데이터가 Document 로 불리며, 이 데이터의 집합을 Collection(RDMS에서는 Table) 이라고 합니다.

스키아 제약 없이 자유롭고, BSON(Binray JSON) 형태로 각 문서가 저장되며 배열이나 날짜 등 기존 RDMS에서 지원하지 않던 형태로도 저장할 수 있기 때문에 관계를 연결하는 JOIN이 필요 없이 한 문서에 좀 더 이해하기 쉬운형태 그대로 정보를 저장할 수 있다는 것이 특징입니다.

문서지향 데이터베이스로, 객체지향 프로그래밍과 잘 맞고 JSON을 사용할 때 아주 유용합니다.

따라서 자바스크립트 기반으로 하는 Node.js와 호환이 매우 좋기 때문에, Node.js에서 가장 많이 사용되는 데이터베이스입니다.

물론 mysql 같은 관계형 데이터베이스 사용도 가능합니다.

  • Join이 없으므로 Join이 필요 없도록 데이터 구조화가 필요
  • 다양한 종류의 쿼리문을 지원(필터링, 수집, 정렬, 정규표현식 등)
  • 관리의 편의성
  • 스키마 없는(Schemaless) 데이터베이스를 이용한 신속 개발, 필드를 추가하거나 제거하는 것이 매우 쉬워짐
  • 쉬운 수평 확장성
  • 인덱싱 제공

SQL vs MongoDB

MySQLMongoDB 를 가장 대표적으로 비교하는데 용어도 서로 다릅니다.

MySQL 용어MongoDB
databasedatabase
tablecollection
indexindex
rowJSON document
columnJSON field
joinembedding and linking
primary key_id field
group byaggregation

SQL 구문MongoDB 구문
CREATE TABLE USERS(a Number, b Number)db.createCollection("mycoll")
INSERT INTO USERS VALUES(3, 5)db.users.insert({a:3, b:5})
SELECT * FROM usersdb.users.find()
SELECT a,b FROM users WHERE age=20db.users.find({age:20}, {a:1, b:1})
SELECT * FROM users WHERE age=20 ORDER BY namedb.users.find({age:20}).sort({name:1})

MongoDB 에서는 질의문이 모두 JSON(BSON) 객체 로 표현됩니다.

MongoDB 의 데이터베이스에 접근하고 조정하는 구문은 자바스크립트 문법에 가까운 모습을 보입니다.

MongoDB 설치

지금부터 MongoDB를 설치해보겠습니다.

이번에는 brew 를 이용하여 패키지를 설치해보겠습니다.

터미널을 열어 아래의 명령어를 입력하여 컴퓨터에 탭을 추가해주세요.

brew tap mongodb/brew

그 후 brew install mongodb-community 를 입력해 무료버전인 mongodb-community를 설치해주세요.

만약 Warning: ......brew link mongodb-community 같은 경고가 뜨면, brew link mongodb-community 를 입력해주시면 정상적으로 설치를 다시 진행할 것 입니다.

brew list 를 입력해 설치되어 있는 패키지 안에서 mongodb-community, mongodb-database-tools, mongosh 가 존재한다면 성공적으로 잘 설치된 것 입니다.

brew services start mongodb-community 를 입력해 mongoDB를 실행시켜주세요.

이 후 아래의 단계를 계속 진행하면서 MongoDB가 잘 실행되고 있는지 확인해보겠습니다.

정상적적으로 mongoDB가 실행되었다면 브라우저를 열어 localhost:27017 에 들어가면 다음과 같은 화면을 확인할 수 있습니다.

MongoDB는 기본적으로 포트는 27017이 고정입니다.

이제 root 사용자를 등록해 비밀번호가 있어야 mongoDB에 접속할 수 있도록 설정해 주겠습니다.

터미널에 mongo 를 입력하면 shell을 사용할 수 있습니다.

shell을 실행시켜주세요.

🚨 zsh: command not found: mongo 에러
해결방법1 : brew services restart mongodb-community 명령어를 입력하여 재시작
해결방법2 : brew install mongodb-community-shell 명령어를 입력하여 설치


기본적으로 mongoDB에 기본적으로 admin 이라는 DB가 존재합니다.

use admin 을 입력해 admin을 선택해주세요.

db.createUser({user:'root', pwd:'12345678', roles:['root']}) 를 입력해 사용자를 등록해 주세요.

🚨 다만 pwd 부분은 반드시 바꿔주세요!



exit 를 입력하여 shell에서 나와주세요.

그리고 brew services restart mongodb-community 를 입력해 MongoDB를 재시작해주세요.

MongoDB 재시작을 해야 root 사용자와 비밀번호를 설정해 놓았던 설정이 적용됩니다.

mongo -u root -p 를 입력하고 비밀번호를 입력해주면 방금 전 생성했던 root 사용자로 접속하게 됩니다.

MongoDB Compass 설치

MongoDB Compass 는 MongoDB용 GUI 데이터를 시각적으로 탐색하는 툴입니다.

DB를 쉽게 조회하고 수정할 수 있습니다.

MongoDB 공식 홈페이지에서 설치 파일을 다운로드 해주세요.

MongoDB Cmopass 설치 : https://www.mongodb.com/try/download/shell

자신의 OS와 사용하려는 버전에 맞게 설치 파일을 다운로드 후 설치를 진행해 주세요.

URI 부분에 mongodb://localhost:27017 입력한 뒤, Connect 버튼을 클릭해 주세요.

연결이 되면 위와 같이 MongoDB Compass에 정상적으로 접속이 된 것을 확인할 수 있습니다.

만약 연결이 안될 경우에는 MongoDB Community 가 실행중인지 확인해 주세요.

Local에서 MongoDB 연결

설치된 mongoDB가 잘 실행되는지 MongoDB shell을 열어 데이터를 추가해보겠습니다.

터미널을 열어 mongo -u root -p 를 입력하여 쉘에 접속합니다.

그런 다음 show databases 명령어로 데이터베이스를 확인해 줍니다.

지금부터 그 중 하나인 local이라는 데이터베이스를 사용해보겠습니다.

use local 명령어를 입력한 뒤 db.product.insert({seller:'철수', name: '마우스', price: 5000}) 을 입력하여 데이터를 넣어보겠습니다.

db.product.find() 명령어를 실행하면 방금 추가한 데이터가 잘 보여집니다.

이를 MongoDB Compass로 확인하여 보겠습니다.

MongoDB COmpass를 실행하여 localhost , 27017 로 포트를 연결해줍니다.

위와 같은 결과의 화면이 보여진다면 정상입니다.

Docker Composs

Docker-compose복수 개의 컨테이너를 실행시키는 도커 애플리케이션이 정의를 하기 위한 툴입니다.

기본적으로 YAML 파일 을 사용하여 애플리케이션의 서비스를 구성할 수 있습니다.

즉, YAML 파일 로 여러 개의 docker 내부 속성을 설정하고 YAML 파일 을 실행시켜 마치 docker를 배치로 한 번에 실행시키는 것과 같다고 생각하시면 됩니다.

Docker-Compose를 활용한 MongoDB 연결

이번에는 Docker-Compose 를 이용해서 위에서 설명했던 MongoDB를 연결해보겠습니다.

08-01-dokcer-compose-with-mongo 폴더를 새로 만들어주세요.

폴더 안에 07-03-docker-with-dockerignore-package.json 파일을 복사 붙여넣기 해주세요.

이제 MongoDB 컨테이너를 띄워야 합니다.

이전에 Dockerfile은 하나의 컴퓨터라고 생각한다고 설명했습니다.

FROM mongo:latest

폴더 안에 docerfile.mongo 를 만들어 주시고 **mongo의 버전을 최신으로 정의했습니다.

백엔드와 mongoDB의 서버를 한번에 실행시키기 위해서 YAML 파일을 정의해주어야 합니다.

.yml 이나 .yaml 둘 다 사용 가능합니다.

현재 폴더에 docker-compose.yaml 파일을 새로 생성해주세요.

version: "3.3"

services:
  backend:
    build:
      context: .
      dockerfile: dockerfile
    ports:
      - 3000:3000

  database:
    build:
      context: .
      dockerfile: dockerfile.mongo
    ports:
      - 27017:27017

컴포즈 파일은 service network 그리고 volume 을 정의합니다.

여기서는 service 만 정의하겠습니다.

service 정의는 각각의 컨테이너에 적용되는 configuration을 포함하고 있습니다.

service 내부에 my_backend와 my_database를 정의해 주었습니다.

변수명과 같은 것입니다.

다른 변수명으로 정의해주셔도 됩니다.

service 내부에 정의된 요소는 다음과 같습니다.

  • context : Dockerfile을 포함하는 디렉토리 경로 또는 git repo의 url입니다.
  • dockerfile : Dockerfile을 대체하는 파일을 지정해 줍니다.

ports 정의는 호스트OS와 컨테이너의 포트를 바인딩 시켜줍니다.

예를 들어 컨테이너의 노출된 포트 3000을 Docker 호스트 컴퓨터(Linux VM)의 포트 3000에 전달합니다.

이제 docker-compose.yaml 파일을 실행시켜 이미지를 빌드해보겠습니다.

docker compose build 를 입력하면 다음과 같이 이미지를 빌드합니다.

docker images 를 입력해서 생성된 이미지들을 확인합니다.

docker compose up 을 입력해 container를 실행시켜줍니다.

DB 서버가 잘 동작하는지 확인해 보겠습니다.
그 전에 터미널에 brew services stop mongodb-community 를 입력하여 서비스를 종료시켜 줍니다.



MongoDB Compass를 실행시켜주세요.

야믈파일에 DB 서버의 port를 27017:27017로 정의해 주었기 때문에 MongoDB Compass의 연결 port를 27017로 정의 후 connect 해주세요.

연결외 되었다면 정상적으로 DB 서버가 실행중인겁니다.

local 데이터베이스를 눌러 확인해보겠습니다.

아까 만든 product collection이 사라졌습니다.

Docker에서 새로 만든 mongoDB에 접속했기 때문에 local에서 만들어준 데이터는 존재하지 않습니다.

Dockerfile.mongodb를 image로 변경

Dockerfile.mongodb를 image로 변경해 보겠습니다.

dockerfile.mongo 로 정의해두었던 mongoDB의 설정을 야믈파일에 직접 정의해 보겠습니다.

08-02-docker-compose-with-mongo-image 폴더를 새로 만들어주세요.

폴더 안에 08-01-docker-compose-with-mongo 파일을 복사 붙여넣기 해주세요.

그리고 08-02-docker-compose-with-mongo-image 폴더 안에 dockerfile.mongo 는 삭제해주세요.

version: "3.3"

services:
  backend:
    build:
      context: .
      dockerfile: dockerfile
    ports:
      - 3000:3000

  database:
    image: mongo:latest
    ports:
      - 27017:27017

기존에 dockerfile.mongo 에 정의해 두었던 monto의 최신 버전을 image에 정의해 주었습니다.

이제 따로 build 에 대한 정의는 필요없으니 지워주었습니다.

이제 docker-compose.yaml 파일을 실행시켜 이미지를 빌드해보겠습니다.

docker compose build 를 입력해주세요.

docker compose up 를 입력해 container를 실행시켜줍니다.

백엔드 서버가 잘 실행되었는지 확인하기 위해서 postman을 실행시켜주세요.

야믈파일에 백엔드 서버의 포트를 3000:3000으로 정의해주었기 때문에 postman에서 요청을 보낼때는 localhost:3000/boards 로 요청을 보내야합니다.

DB 서버가 잘 실행하는지 MongoDB Compass로 확인해보겠습니다.

아까와 똑같이 야믈파일에 DB 서버의 포트를 27017:27017로 정의해주었기 때문에 MongoDB Compass의 연결 포트를 27017로 정의 후 Connect 해주세요.



ODM(Object Document Mapping) & Mongoose

MongooseNode.js와 MongoDB를 위한 ODM(Object Data Mapping) library입니다.

이번에는 직접 스키마를 작성해 실제 데이터베이스와 연결하여 요청을 보내 데이터를 생성하고 생성된 데이터를 읽어오는 작업까지 해보겠습니다.

08-03-rest-api-with-mongoose-1 폴더를 새로 만들어주세요.

폴더 안에 08-02-docker-compose-with-mongo-image 폴더 안에있는 모든 파일을 복사 붙여넣기 해주세요.

그리고 터미널을 열어서 mongoose 라이브러리를 설치해주세요.

npm install mongoose
or
yarn add mongoose

Defining a Model

Model 정의를 위해 model 폴더를 생성해주시고 폴더 안에 board.model.js 파일을 만들어주세요.

import mongoose from "mongoose";

const boardSchema = new mongoose.Schema({
    writer: String,
    title: String,
    contents: String
})

export const Board = mongoose.model('Board', boardSchema);

mongoose 라이브러리를 사용하기 위해서 먼저 불러옵니다.

새로운 스키마를 boardSchema 변수에 담아서 선언하고 내부에는 다음과 같이 요소들의 key 값의 타입을 지정해 주었습니다.

model() 메서드 를 사용하여 문자열과 schema를 전달하여 model을 생성합니다.

첫번째 인자는 해당 collection의 단수적 표현을 나타내는 문자열입니다.

생성된 model 을 외부에서 접근할 수 있도록 export 해주었습니다.

mongoose의 스키마는 mongoDB에 저장되는 document의 Data 구조. 즉 필드 타입에 관한 정보를 JSON 형태로 정의한 것 입니다.

Mongoose Schema는 다음의 Data Type을 지원합니다.

Connecting to MongoDB

이번에는 프로젝트 내에 mongoDB를 연결해보겠습니다.

index.js 게시물을 등록하고 등록된 게시물을 읽어오는 로직을 작성하겠습니다.

index.js 파일에 다음을 추가해서 mongoDB를 연결해주세요.

mongoose.connect("mongodb://database:27017/database")

앱이 하나의 데이터베이스만 사용하는 경우 mongoose.connect 를 사용하고 추가 연결을 생성해야 하는 경우 mongoose.createConnection 을 사용합니다.

mongoose.connect('mongodb://localhost:27017/database') 의 형태로 작성됩니다.

POST 데이터 등록

import mongoose from 'mongoose';
import Board from './model/board.model.js'

// ... 기존 코드

app.post('/board', async (req, res) => {
    // 데이터를 등록하는 로직 (DB에 저장하기)
    
    const board = new Board({writer: req.body.writer, title: req.body.title, contents: req.body.contents});
    await board.save();

    res.send('등록에 성공하였습니다.');
})

// ... 기존 코드

/board endpoint를 지정해서 POST 요청을 받았을 때 JSON 데이터를 담은 BODY에서 각각의 요소를 하나하나 빼와서 연결해 놓은 mongoDB의 boards collection에 저장해줍니다.

GET 데이터 조회

app.get('/boards', async (_, res) => {
    // 데이터를 조회하는 로직 (DB에서 꺼내오기)

    const boards = await Board.find();
    res.send(boards);
});

/boards endpoint를 지정해서 연결된 mongoDB의 boards collection에 저장된 모든 데이터를 조회해서 응답해줍니다.

find 는 보통 모든 데이터를 조회할 때 사용되며, findOne특정 데이터만 조회할 때 자주 사용됩니다.

실습

이제 postman을 사용해서 직접 통신을 해보겠습니다.

먼저 docker를 이용해서 서버를 실행시키겠습니다.

  1. docker compose build 를 입력해 docker image를 생성해주세요.
  2. docer compose up 을 입력해 container를 실행시켜 주세요.

이제 postman을 실행시켜주세요.

먼저 데이터를 등록해보겠습니다.

POST 메서드를 선택해주시고 localhost:3000/board 를 입력해 주세요.

Body를 입력해주기 위해서 raw를 선택하고 다음과 같이 JSON 데이터를 입력해 주세요.

{
    "writer": "yeontan0826",
    "title": "this is title",
    "contents": "this is contents!!!!"
}

그리고 Send를 클릭해 요청을 보내보세요.

이번엔 등록된 데이터를 조회해보겠습니다.

GET 메서드를 선택해주시고, localhost:3000/boards 를 입력해주세요.

그리고 Send를 클릭해 요청을 보내보겠습니다.

정상적으로 데이터를 저장하고 불러왔습니다.

마지막으로 mongoDB-compass 를 실행해서 생성한 DB와 collection과 저장한 데이터를 확인해 보겠습니다.

정상적으로 데이터가 삽입되어있는 것을 확인하실 수 있습니다.

0개의 댓글