본문 바로가기
컴퓨터/웹 : JS

[Node.js] express + mongoDB 데이터 연동//CRUD작업

by 도도새 도 2023. 1. 7.

express+mongo:CRUD

 

* 본 게시글은 작성자가 기존 공부 내용을 복습하고 새로운 프로젝트를 진행하는 기록을 위함입니다. 오류 지적은 언제나 환영합니다. 감사합니다.

 

* 혹시나 제가 공부하는 과정을 따라서 실습해 볼 분은 제가 진행한 순서대로 따라오면 될 것 같습니다. 현재까지 아래의 순서를 따릅니다.

 

 

 

이번에는 몽고DB를 express와 연결해 생성 조회 삭제하는 간단한 예제를 구현한다.

이 과정에서 내가 추후 기억하고자 하는 지식이 (대략적으로) 기록되어 있다.

 

 

HTTP Method 네 가지

 

REST란?

REST API란 REST의 특징을 지키면서 API를 제공하는 것을 의미한다. 여기서 REST란 REpresentational State Transfer의 약자이다. 이는 HTTP 프로토콜에 있는 Method를 활용한 아키텍처 스타일이다.

 

HTTP Method 이름 수행하는 동작
GET 조회
POST 생성
PUT / PATCH 수정
DELETE 삭제

 

 이번에는 이 GET/POST/PUT/DELETE 동작을 구현하기 위하여 npm에서 method-override모듈을 사용한다.

https://www.npmjs.com/package/method-override

 

method-override

Override HTTP verbs. Latest version: 3.0.0, last published: 4 years ago. Start using method-override in your project by running `npm i method-override`. There are 1366 other projects in the npm registry using method-override.

www.npmjs.com

 

 해당 모듈은 PUT, DELETE와 같은 것을 지원해주지 않는 곳에서도 해당 동작을 수행 할 수 있게 도와준다.

작업하고자 하는 폴더의 터미널에서 아래 명령어를 입력한다.

npm i method-override

 

 app.js파일에

app.use(methodOverride('_method'))

한 줄을 추가한다. 이제 put, delete 역시 사용 가능하다.
 

일반적으로 데이터를 보내기 위해 html의 form태그를 이용하게 되는데, PUT과 DELETE(일반적으로 수정 삭제)를 사용할 경우 form의 method속성에 method="post"로 사용하게 된다.

 

 내부적으로는 이 post와 delete가 일종의 가짜라고 한다. 그래서 보낸 정보를 .delete나 .post메서드로 받기 위해 action의 url주소 뒤에 ?_method=DELETE 혹은?_method=POST을 붙이면 정상 작동한다.

 

예시

    <form action="/cafe?_method=DELETE" method="post">
        <button>전부 삭제</button>
    </form>
 
 

몽고DB와 Mongoose

 

 몽고 DB를 연결한다. 몽고DB를 Node.JS에서 사용하기 위해 Mongoose를 사용할 것이다.

 

몽고 DB란 일종의 데이터베이스인데 기존에 많이 사용하던 SQL 데이터 베이스와는 사뭇 다른 무언가이다.(추후 몽고DB에 대해 자세히 정리 할 것! 위키피디아 -> )https://ko.wikipedia.org/wiki/%EB%AA%BD%EA%B3%A0DB

 

Mongoose는 몽고DB를 express에서 사용할 수 있게 해주는 라이브러리이다. 어쨌든, 몽고DB를 깔고 몽구스 역시 다운로드 하여야한다.

 

1. 몽고 DB다운로드

https://www.mongodb.com/try/download/community-kubernetes-operator

 

Try MongoDB Community Edition

Try MongoDB Community Edition on premise non-relational database including the Community Server and Community Kubernetes Operator for your next big project!

www.mongodb.com

 

2. Mongoose다운로드

 

터미널에 아래와 같이 입력한다.

npm i mongoose

https://www.npmjs.com/package/mongoose

 

mongoose

Mongoose MongoDB ODM. Latest version: 6.8.2, last published: 9 days ago. Start using mongoose in your project by running `npm i mongoose`. There are 13183 other projects in the npm registry using mongoose.

www.npmjs.com

 

이후 models라는 새로운 폴더 안에 cafe.js라는 파일을 만든다. 이곳에서 mongoose를 이용한 모델을 생성할 것이다.

카페하면 무엇이 있어야 할까? 시작으로 간단하게 카페이름, 위치, 메뉴 정도만 구성하도록 하겠다.

 

/models/cafe.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

 

const cafeSchema = new Schema({
  name: String,
  menu: [String],
  location: String
});

 

module.exports = mongoose.model('Cafe', cafeSchema);
name, menu, location을 가지는 스키마를 생성한다.

 

Views 생성

 

 간단하게 몽고DB와 몽구스를 사용하기 위해 홈페이지와 create를 위한 페이지, 그리고 그것을 모두 보여주기 위한 페이지 세 개를 만든다. Views 폴더를 만들고 그 안에 세 개의 ejs파일을 만든다.

 

ejs는 embedded javascript의 약자로, 쉽게 말해 js 코드를 html코드 내에서 사용할 수 있게 도와준다. ejs사용을 위해 ejs를 다운로드하고 app.js에 몇 줄을 추가한다.

npm i ejs

 

https://www.npmjs.com/package/ejs

 

ejs

Embedded JavaScript templates. Latest version: 3.1.8, last published: 8 months ago. Start using ejs in your project by running `npm i ejs`. There are 11821 other projects in the npm registry using ejs.

www.npmjs.com

//app.js
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.set('views', path.join(__dirname, 'views'));app.set('view engine', 'ejs'); : 뷰 엔진으로 ejs를 사용하겠다는 의미이다.

app.set('views', path.join(__dirname, 'views')); // 기본 경로로 __dirname + views 이름의 폴더를 사용하겠다는 의미이다. 이렇게 하여 후에 경로를 앞에서부터 접근하지 않고 바로 views 폴더에 접근 할 수 있다.

 

 이제 할 작업은 Views폴더 내에 post동작을 하는 form을 넣을 것이다.이를 위해서는 form의 name속성에 값을 부여하면 된다. 즉, 데이터가 name속성에 입력한 대로 전달될 것이다.

문제는 어떻게, 이다. 이후 post메서드로 해당 값을 받기 위해서는 req.body를 읽어야한다. 문제는 express에서 body를 읽어오기 위해서는 body-parser라는 모듈을 추가로 설치하여야한다.(최신 버전들은 기본적으로 내장되어 있을 것)

 

사용을 위해 app.js에 아래 한 줄을 입력한다.

app.use(express.urlencoded({extended:true}));

 

*주의 : body-parser은 오직 json과 unincoded데이터만을 다룬다. 따라서 input의 속성 중 enctype을 multipart/form-data로 주면 제대로 작동하지 않는다.

 

views/cafe.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>카페를 보여주는 페이지</title>
</head>
<body>
    <% for(let cafe of cafes) { %>
        <h1>카페 이름</h1>
        <h3><%= cafe.name %></h3>
        <h1>카페 메뉴</h1>
        <h3><%= cafe.menu %></h3>
        <h1>카페 위치</h1>
        <h3><%= cafe.location %></h3>
    <% } %>

 

    <form action="/cafe?_method=DELETE" method="post">
        <button>전부 삭제</button>
    </form>
</body>
</html>
받아온 cafes의 데이터의 각 요소를 들며 해당 객체의 name, menu, location의 값을 출력한다.

 

*for in문과 for of문의 차이 : for in 문은 key값의 value에 접근 할 수 없지만 for of는 가능하다. 기타 차이점들이 있지만, 이번에는 이 부분이 가장 중요하다.

 

views/createCafe.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>카페 만들기</title>
</head>
<body>
    <form action="/cafe" method="POST">
        <label for="cafeName">카페 이름</label>
        <input id="cafeName" type="text" name="name"> <!-- name속성 : 서버로 전달되는 이름-->
        <label for="menuName">메뉴 이름</label>
        <input id="menuName" type="text" name="menu">
        <label for="cafeLocation">카페 위치</label>
        <input id="cafeLocation" type="text" name="location">
        <button>입력</button>
    </form>
</body>
</html>

 

views/home.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>홈페이지</title>
</head>
<body>
    <h1>카페 정보 사이트 !!</h1>
    <form action="/createCafe">
        <button>카페 생성</button>
    </form>
</body>
</html>
form의actoin이 예제처럼 된 경우 /createCafe 주소로 들어온 경우  get메서드로 처리한다.

 

최종

 

app.js

const express = require('express');
var methodOverride = require('method-override')
const app = express();
const path = require('path');
 
/*DataBase*/
const Cafe = require('./models/cafe');
const mongoose = require('mongoose');
 
const port = process.env.PORT || 3000;
mongoose.set('strictQuery', false);
mongoose.connect("mongodb://127.0.0.1:27017/Cafe")//몽고 DB연결
  .then(() => {
    console.log("MongoDB is connected");
  })
  .catch((err) => {
    console.log(err);
  });
 
  /*view*/
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(express.urlencoded({extended:true}));//body-parser 사용
app.use(methodOverride('_method'))
 
 
 
app.get('/', (req, res)=>{//   '/'의 주소를 받은 경우
    res.render('home')  // views의 home을 랜더링하여 보여줌
});

 

app.get('/createCafe', (req, res)=>{
    res.render('createCafe');
})

 

app.get('/cafe', async(req, res)=>{
    const cafes = await Cafe.find({}); // DB의 모든 내용을 cafes에 저장
    res.render('cafe', {cafes}); // 해당 객체를 cafe.ejs로 넘겨줌
})
 
app.post('/cafe', async(req, res)=>{//create cafe
    const cafe = new Cafe(req.body);
    await cafe.save(); ; // document 생성 및 저장
    res.redirect('/cafe'); // /cafe주소로 리다이렉트
})
 
app.delete('/cafe', async(req, res)=>{
    await Cafe.deleteMany({});// Cafe 도큐먼트의 모든 데이터 삭제
    res.redirect('/cafe');
})
 
app.listen(port, ()=>{
    console.log(`연결 : ${port}`)
})

 

최종적으로 데이터를 쓰고(create), 읽고(read), 삭제(delete)하는 코드를 작성하였다. 이것을 발전시켜서 최종적인 프로젝트를 만들도록 하겠다.

 

 

실행은 터미널에 mongod(mongod 오류가 뜨면 mongod --ipv6 시도)를 친 후 실행중인 상태에서, node app.js를 하면 된다. 그럼 localhost:3000에서 웹이 실행 될 것이다.

 

 

댓글