본문 바로가기

mongoDB

[MongoDB] Node.js express CRUD with mongoDB

반응형

 

Node.js, express with mongoDB로 application 만들기 

 

 

1. vsc 기본 세팅 

- MONGODB_CRUD 폴더 > server.js 파일 생성 

- 터미널 경로 MONGODB_CRUD에서 npm init  

npm init

- 필요한 packages 다운

npm install express morgan nodemon ejs body-parser dotenv mongoose axios 

express : 

morgan : HTTP request logger middleware for node.js (It logs requests.)

nodemon : 변경 사항있을 때 자동으로 server on (오직 js 파일 변경 시에만 ! html X ) 

ejs : 템플릿 엔진 (템플릿을 읽어 엔진의 문법과 설정에 따라 파일을 html 형식으로 변환시키는 모듈) 

body-parser : 

dotenv : 

mongoose : 

axios : 

 

* 템플릿 엔진이란?
동적인 결과를 정적인 파일에 담기위해 사용 / 정적인 파일만을 서비스하면 필요없다. 

JS 코드로 연산된 결과를 변수에 넣고 변수를 뷰 파일에서도 사용할 수 있게끔 한다.
템플릿 엔진은 클라이언트 요청에 따라 웹문서 들어가는 내용(결과)이 달라질 수 있어서 정적인 부분과 동적인 부분을 따로하기 위해 사용한다. 

 

- package.json 의 "scripts" - "start": "node server.js" 를 -> nodemon server.js 로 변경

{
  "name": "mongodb_crud",
  "version": "1.0.0",
  "description": "crud with express and mongodb",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon server.js"      // 요로코롬
  },
  "keywords": [
    "crud",
    "mongodb"
  ],
  "author": "emily",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.21.4",
    "body-parser": "^1.19.0",
    "dotenv": "^10.0.0",
    "ejs": "^3.1.6",
    "express": "^4.17.1",
    "mongoose": "^6.0.7",
    "morgan": "^1.10.0",
    "nodemon": "^2.0.13"
  }
}

 

 

MVC 패턴

Model, View, Controller 기반 폴더 구조 생성 

- MONGODB_CRUD > assets 폴더 > css, js, img 폴더 생성 

- MONGODB_CRUD > views 폴더 생성 (모든html 파일) 

- MONGODB_CRUD > server 폴더 생성 (서버 측 코드 ex. 서비스, 모델, mongodb 연결) 

- MONGODB_CRUD > server > controller, model, database, routes, services 폴더 생성

 

* database : database connection을 위한 폴더 

* routers : router역할 

* Model : mongodb로 작업, 데이터 유효성 검사, 데이터 처리 등 

* controller : 리소스에 대한 사용자 요청 

 

 

 

 

 

2. server.js 코드 작성 및 실행 / 필요한 packages 가져와서 설정 

server.js

const express = require('express');
const app = express();
const PORT = process.env.PORT || 8080; 

app.get('/', (req,res)=>{
    res.send('CRUD with mongoDB');
})

app.listen(PORT, ()=>{
    console.log(`Server is running on http://localhost:${PORT}`)
})

 

 

- MONGODB_CRUD > config.env 파일 생성 및 변수 작성 

- server.js 에 dotenv 설정, path 정해주기 (const PORT 변수 보다 위에 선언 되어야함 ****

const express = require('express');
const app = express();

const dotenv = require('dotenv');
dotenv.config({path:'config.env'})
const PORT = process.env.PORT || 8080; 

app.get('/', (req,res)=>{
    res.send('CRUD with mongoDB');
})

app.listen(PORT, ()=>{
    console.log(`Server is running on http://localhost:${PORT}`)
})

 

-> PORT 3000으로 잘 찍힘 

 

 

 

 

지금까지는 env 파일 이름을 모두 .env 라고 명명하고 server.js 에서 쓸 때는 dotenv.config(); 요렇게만 썼었다 !

env 파일 명이 .env 가 아니라면  dotenv.config({path:'[파일명].env'}) 를 써줘야 함 ! 

 

 

 

Modules

- morgan 가져오기 

const express = require('express');
const app = express();
const morgan = require('morgan');          //1

const dotenv = require('dotenv');
dotenv.config({path:'config.env'});
const PORT = process.env.PORT || 8080; 

// log requests 
app.use(morgan("tiny"));                     //2

"tiny"는 morgan의 predefined format string이다 

predefined format stirng으로는 dev, short, common, combined 등이 있다. 이 인자값에 따라 log도 다르게 된다. 개발 시에는 short / dev를 많이 쓰고 배포 시에는 common, combined를 많이 쓴다고 한다!

 

 

- bodyparser 가져오기 / ejs 설정  

const express = require('express');
const app = express();
const morgan = require('morgan');
const bodyParser = require('body-parser');     //  1
const path = require('path');   //built-in 

const dotenv = require('dotenv');
dotenv.config({path:'config.env'});
const PORT = process.env.PORT || 8080; 

// log requests
app.use(morgan("tiny"));
// parse request to body-parser
app.use(bodyParser.urlencoded({extended:true}));   //  2

// set view engine
app.set("view engine", "ejs");                  //  3
// views 안에 ejs 폴더를 만들어 사용시 아래처럼 path 설정해줘야함 
//app.set("views", path.resolve(__dirname, "views/ejs"))            //  4 (이건optional) 

app.get('/', (req,res)=>{
    res.send('CRUD with mongoDB');
})

app.listen(PORT, ()=>{
    console.log(`Server is running on http://localhost:${PORT}`)
})

ejs 파일들을 담긴 경로를 app.set('views', path.resolve(__dirname, "위치")) 요렇게 설정해 주기도 한다! 여기선 할 필요가 없어서 패스 

이전까지는 nunjucks로 해왔는데 요 역할을 ejs 가 해주는 것 같다 

 

 

- assets 설정 

.
.

// load assets
app.use('/css', express.static(path.resolve(__dirname, "assets/css")));
app.use('/img', express.static(path.resolve(__dirname, "assets/img")));
app.use('/js', express.static(path.resolve(__dirname, "assets/js")));

.
.

이렇게 css 폴더 경로 설정을 하면 css/style.css 이런 식으로 경로 고민없이 css 폴더 안의 css 파일을 바로 쓸 수 있다. 

img, js 도 마찬가지!

 

 

 

 

 

3. Views

views > index.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>CRUD Application</title>
</head>
<body>
    
    <!-- Header -->
    <header id="header">
        <nav>
            <div class="container">
                <div class="text-center">
                    <a href="/" class="nav-brand text-dark">User Management System</a>
                </div>
            </div>
        </nav>
    </header>
    <!-- /Header -->

</body>
</html>

다시 서버를 키고 localhost:3000 들어가면 아직 res.send('CRUD ~~~') 요 String이 나온다.

이제 위에 만든 index.ejs 를 뿌리도록 코드 작성하기

server.js

// set view engine
app.set("view engine", "ejs");
// views 안에 ejs 폴더를 만들어 사용시 아래처럼 path 설정해줘야함 
//app.set("views", path.resolve(__dirname, "views/ejs"))

.
.
.

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

index.ejs 파일을 적어주는데 .ejs 확장자를 안써줘도 되는 이유는 위에 app.set에서 view engine ejs 로 설정해놨기 때문! 예전에 html nunjucks로 했을 때 html로 적은 기억이 난다.

 

다시 새로고침을하면 index.ejs html 내용이 render된다. 

 

 

 

 

4. header footer 나누기 

MONGDB_CRUD > views > include 폴더 생성 > _header.ejs, _footer.ejs 파일 생성

- _header.ejs 에 index.ejs top to /Header 까지 붙여넣기 

- _footer.ejs 에 나머지 붙여넣기

- index.ejs 에 include 문법 넣기 

 

_header.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>CRUD Application</title>
</head>
<body>
    
    <!-- Header -->
    <header id="header">
        <nav>
            <div class="container">
                <div class="text-center">
                    <a href="/" class="nav-brand text-dark">User Management System</a>
                </div>
            </div>
        </nav>
    </header>
    <!-- /Header -->

_footer.ejs

</body>
</html>

index.ejs

<!-- include header -->
<%- include('include/_header.ejs')%>
<!-- /include header -->


<!-- include footer -->
<%- include('include/footer.ejs')%>
<!-- /include footer -->

 

 

 

 

 

 

5. Live Server Extenstion 

서버를 다시 off -> on 하고 브라우저 새로고침하는 번거로움 없애기 

 

views > index.html 파일 생성 & _header.ejs, _footer.ejs 안 코드 붙여넣기

index.html

<!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>CRUD Application</title>
</head>
<body>
    
    <!-- Header -->
    <header id="header">
        <nav>
            <div class="container">
                <div class="text-center">
                    <a href="/" class="nav-brand text-dark">User Management System</a>
                </div>
            </div>
        </nav>
    </header>
    <!-- /Header -->
    
</body>
</html>

Live server 다운 

Open with live server 클릭 -> 브라우저 열림 -> html 수정하면 자동으로 새로고침됨 ! 

 

 

 

 

 

 

5. Main section 

views > index.html 

main site 코드 추가 & 아이콘 추가

 

 

아이콘 추가 방법

google font awesome cdn !

https://cdnjs.com/libraries/font-awesome

 

font-awesome - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers

The iconic SVG, font, and CSS toolkit - Simple. Fast. Reliable. Content delivery at its finest. cdnjs is a free and open-source CDN service trusted by over 12.5% of all websites, serving over 200 billion requests each month, powered by Cloudflare. We make

cdnjs.com

첫번째 코드 주소 복사 -> index.html head section에 붙여넣기 

<!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>CRUD Application</title>
    요고 ↓↓
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta2/css/all.min.css" integrity="sha512-YWzhKL2whUzgiheMoBFwW8CKV4qpHQAEuvilg9FAn5VJUDwKZZxkJNuGM4XkWuk94WCrrwslk8yWNGmY1EduTA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
</head>
<body>

 

google font awesome icons 검색

https://fontawesome.com/v5.15/icons?d=gallery&p=2&m=free 

 

Font Awesome

The world’s most popular and easiest to use icon set just got an upgrade. More icons. More styles. More Options.

fontawesome.com

user 검색 -> 원하는 icon 클릭 -> html 복사 

 

index.html 에 복사한 코드 넣기 

    <!-- Main site -->
        <main id="site-main">
            <div class="container">
                <div class="box-nav d-flex justify-between">
                    <a href="/add-user" class="border-shadow">
                    <span class="text-gradient">New User
                    	<!-- 요고 ↓↓↓ --> 
                        <i class="fas fa-user-circle"></i>
                    </span>
                    </a>
                </div>
            </div>
        </main>
    <!-- /Main site -->

요렇게 나왔다.

index.html - table 추가 

<!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>CRUD Application</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta2/css/all.min.css" integrity="sha512-YWzhKL2whUzgiheMoBFwW8CKV4qpHQAEuvilg9FAn5VJUDwKZZxkJNuGM4XkWuk94WCrrwslk8yWNGmY1EduTA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
</head>
<body>
    
    <!-- Header -->
    <header id="header">
        <nav>
            <div class="container">
                <div class="text-center">
                    <a href="/" class="nav-brand text-dark">User Management System </a>
                </div>
            </div>
        </nav>
    </header>
    <!-- /Header -->

    <!-- Main site -->
        <main id="site-main">
            <div class="container">
                <div class="box-nav d-flex justify-between">
                    <a href="/add-user" class="border-shadow">
                    <span class="text-gradient">New User
                        <i class="fas fa-user-circle"></i>
                    </span>
                    </a>
                </div>

                <!-- form handling-->
                <form action="/" method="POST">
                    <table class="table">
                        <thead class="thead-dark">
                            <tr>
                                <th>ID</th>
                                <th>Name</th>
                                <th>@Email</th>
                                <th>Gender</th>
                                <th>Status</th>
                                <th>Action</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td>1</td>
                                <td>Username</td>
                                <td>exameple@gmail.com</td>
                                <td>Female</td>
                                <td>Active</td>
                                <td>
                                    <a href="#" class="btn border-shadow update">
                                        <span class="text-gradient"><i class="fas fa-pencil-alt"></i></span>
                                    </a>
                                    <a class="btn border-shadow delete">
                                        <span class="text-gradient"><i class="fas fa-times"></i></span>
                                    </a>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </form>


            </div>
        </main>
    <!-- /Main site -->

</body>
</html>

 

 

 

 

6. Styling HTML (CSS) + responsive application

- index.html <head> 안에 css추가 

    <link rel="stylesheet" href="../assets/css/style.css">

- font 가져오기 

https://fonts.google.com/

 

Google Fonts

Making the web more beautiful, fast, and open through great typography

fonts.google.com

폰트 2개 select : font names = barlow - regular 400 , pt sans - regular 400 

import 누르고 파란 부분만 복사 -> assets > css > style.css 에 붙여넣기 

@import url('https://fonts.googleapis.com/css2?family=Barlow&family=PT+Sans&display=swap');

/* 변수 만들기 */
:root{
    --dark:#2b2d42;
    --light:#adb5bd;
    --border:#dee2d6;
    --border-btn:#edf2f4;
}

*{
    padding:0;
    margin:0;
    box-sizing: border-box;
}

a{
    text-decoration:none;
    font-family: 'PT Sans', sans-serif;
}

쓸 폰트만 google 의 아래 파란 부분만 복사해서 사용 

 

 

나머지 부분들 CSS 추가 

* CSS 전 * 

* CSS 후 * 

row hover 기능도 있다!

 

 

 

 

 

7. Table & Form 

Let's make this table reponsive !

/* make it responsive! */
@media only screen and (max-width:1024px){
    table, thead, tbody, th, td, tr{
        display: block;
    }
    
    thead tr{
        position:absolute;
        top:-9999px;
        left:-9999px;
    }

    tr {border:1px solid var(--border);}

    td{
        border:none;
        position:relative;
    }

}

 

 

 

 

 

 

FORM 

view > add_user.html 생성 및 코드 작성 

- index.html 의 모든 코드 복사 & 붙여넣기 -> form handling 부분 코드 모두 삭제 

 

form 코드 수정 

        <!-- form handling-->
        <form method="POST" id="update_user">
            
        </form>

브라우저 add_user.html로 들어가기 

    <!-- Main site -->
    <main id="site-main">
      <div class="container">
        <div class="box-nav d-flex justify-between">
         
        </div>

        <!-- form handling-->
        <form method="POST" id="update_user">
            
        </form>
      </div>
    </main>
    <!-- /Main site -->
  </body>
</html>

main site 쪽 안에 불필요한 코드 삭제 

 

입력 form 코드 작성 

<!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>CRUD Application</title>
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta2/css/all.min.css"
      integrity="sha512-YWzhKL2whUzgiheMoBFwW8CKV4qpHQAEuvilg9FAn5VJUDwKZZxkJNuGM4XkWuk94WCrrwslk8yWNGmY1EduTA=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    />
    <link rel="stylesheet" href="../assets/css/style.css" />
  </head>
  <body>
    <!-- Header -->
    <header id="header">
      <nav>
        <div class="container">
          <div class="text-center">
            <a href="/" class="nav-brand text-dark">User Management System </a>
          </div>
        </div>
      </nav>
    </header>
    <!-- /Header -->

    <!-- Main site -->
    <main id="site-main">
      <div class="container">
        <div class="box-nav d-flex justify-between">
            <div class="filter">
                <a href="/"><i class="fas fa-angle-double-left"></i>All Users</a>
            </div>
        </div>
        <div class="form-title text-center">
            <h2 class="text-dark">
                New User
            </h2>
            <span class="text-light">
                Use the below form to create a new account
            </span>
        </div>

        <!-- form handling-->
        <form method="POST" id="update_user">
            <div class="new_user">
                <div class="form-group">
                    <label for="name" class="text-light">Name</label>
                    <input type="hidden" name="id" value="">
                    <input type="text" name="name" value="" placeholder="Name">
                </div>
                <div class="form-group">
                    <label for="Email" class="text-light">Email</label>
                    <input type="text" name="email" value="" placeholder="example@gmail.com">
                </div>
                <div class="form-group">
                    <label for="gender" class="text-light">Gender</label>
                    <div class="radio inline">
                        <input type="radio" name="gender" value="Male">
                        <label for="gender" class="radio-label">Male</label>
                    </div>
                    <div class="radio inline">
                        <input type="radio" name="gender" value="Female">
                        <label for="gender" class="radio-label">Female</label>
                    </div>
                </div>
                <div class="form-group">
                    <label for="gender" class="text-light">Status</label>
                    <div class="radio inline">
                        <input type="radio" name="status" value="Active">
                        <label for="gender" class="radio-label">Active</label>
                    </div>
                    <div class="radio inline">
                        <input type="radio" name="gender" value="Inactive">
                        <label for="gender" class="radio-label">Inactive</label>
                    </div>
                </div>
                <div class="form-group">
                    <button type="submit" class="btn text-dark update">Save</button>
                </div>
            </div>
        </form>
      </div>
    </main>
    <!-- /Main site -->
  </body>
</html>

 

 

 

8. Add styling 

style.css (아까 index.html을 그대로 복사해서 add_user.html을 만듬 - 거기에 style.css 코드가 들어가 있다!) 

.
.
.

/*  ADD USER & UPDATE USER TEMPLATE */
.form-title{
    margin-top:2em;
}

.form-title>h2{
    padding:.5em 0;
}

.new_user{
    max-width:786px;
    margin:auto;
}

#update_user .form-group,
#add_user .form-group{
    margin:.4em 0;
}

#update_user .form-group input[type="text"],
#add_user .form-group input[type="text"]{
    width:100%;
    padding:.6em 1em;
    margin: .5em 0;
    border:1px solid var(--border);
    font-family: 'Barlow', sans-serif;
    font-size:1em;
    border-radius:.2em;
}

#update_user .form-group .radio,
#add_user .form-group .radio{
    margin:1em 2em;
}

/* adding style to radio buttons */
.radio input[type="radio"]{
    position: absolute;
    opacity: 0;
}

.radio input[type="radio"] + .radio-label:before{
    content:"";
    background:var(--border-btn);
    border-radius: 100%;
    border:1px solid var(--border);
    display: inline-block;
    width:1em;
    height:1em;
    position: relative;
    top:-0em;
    margin-right:.5em;
    vertical-align: top;
    cursor: pointer;
    text-align: center;
    -webkit-transition: all 250ms ease;
    transition:all 250ms ease;
}

.radio input[type="radio"]:checked + .radio-label:before{
    background-color: #16db93;
    box-shadow: inset 0 0 0 4px #e0ecef;
}   

.radio input[type="radio"]:focus + .radio-label:before{
    outline: none;
    border-color: #16db93;
}

.radio input[type="radio"]:disabled + .radio-label:before{
    box-shadow: inset 0 0 0 4px #e9ecef;
    border-color: #b4b4b4;
    background: #b4b4b4;
}

radio 클릭해도 아직 동작을 안한다 ! -> html lable id 설정해주기 

 

9. Label 설정하기 

add_user.html 

        <!-- form handling-->
        <form method="POST" id="update_user">
            <div class="new_user">
                <div class="form-group">
                    <label for="name" class="text-light">Name</label>
                    <input type="hidden" name="id" value="">
                    <input type="text" name="name" value="" placeholder="Name">
                </div>
                <div class="form-group">
                    <label for="Email" class="text-light">Email</label>
                    <input type="text" name="email" value="" placeholder="example@gmail.com">
                </div>
                <div class="form-group">
                    <label for="gender" class="text-light">Gender</label>
                    <div class="radio inline">
                        <input type="radio" id="radio-2" name="gender" value="Male">
                        <label for="radio-2" class="radio-label">Male</label>
                    </div>
                    <div class="radio inline">
                        <input type="radio" id="radio-3" name="gender" value="Female">
                        <label for="radio-3" class="radio-label">Female</label>
                    </div>
                </div>
                <div class="form-group">
                    <label for="gender" class="text-light">Status</label>
                    <div class="radio inline">
                        <input type="radio" id="radio-4" name="status" value="Active">
                        <label for="radio-4" class="radio-label">Active</label>
                    </div>
                    <div class="radio inline">
                        <input type="radio" id="radio-5" name="status" value="Inactive">
                        <label for="radio-5" class="radio-label">Inactive</label>
                    </div>
                </div>
                <div class="form-group">
                    <button type="submit" class="btn text-dark update">Save</button>
                </div>
            </div>
        </form>

input 에 id를 추가, label for ="해당 id" 

아래처럼 클릭이 가능해짐 

 

 

 

10. Save 버튼 css 추가하기

style.css 

#update_user .form-group .btn,
#add_user .form-group .btn{
    width:100%;
    padding: .9em 1em;
    background-color: #16db93;
    border:none;
    font-family: 'PT Sans', sans-serif;
    font-size: 1em;
    cursor:pointer;
    border-radius: .2em;
    margin: .5em 0;
}

#update_user .form-group .btn:hover,
#add_user .form-group .btn:hover{
    background-color: var(--dark);
    color:var(--border);
}

 

 

 

 

11. html -> ejs 

html을 ejs 템플릿 엔진으로 바꾸기 

 

1) index.html의 Main site 부분 복사 -> index.ejs 의 header & footer 사이에 붙여넣기 

2) index.ejs 의 tr 부분 잘라내기 -> views > include > _show.ejs 파일 만들어 붙여넣기 -> index.ejs 의 잘라내진 공간에 include 문법 ㄱ ㄱ

index.ejs

<!-- include header -->
<%- include('include/_header.ejs')%>
<!-- /include header -->

    <!-- Main site -->
    <main id="site-main">
        <div class="container">
          <div class="box-nav d-flex justify-between">
            <a href="/add-user" class="border-shadow">
              <span class="text-gradient">
                  New User
                <i class="fas fa-user-circle"></i>
              </span>
            </a>
          </div>
  
          <!-- form handling-->
          <form action="/" method="POST">
            <table class="table">
              <thead class="thead-dark">
                <tr>
                  <th>ID</th>
                  <th>Name</th>
                  <th>@Email</th>
                  <th>Gender</th>
                  <th>Status</th>
                  <th>Action</th>
                </tr>
              </thead>
              <tbody>
                <%- include('include/_show.ejs')%>
              </tbody>
            </table>
          </form>
        </div>
      </main>
      <!-- /Main site -->

<!-- include footer -->
<%- include('include/_footer.ejs')%>
<!-- /include footer -->

3) _header.ejs 에 font link & css link 추가 

<!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>CRUD Application</title>
    
    <link
    rel="stylesheet"
    href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta2/css/all.min.css"
    integrity="sha512-YWzhKL2whUzgiheMoBFwW8CKV4qpHQAEuvilg9FAn5VJUDwKZZxkJNuGM4XkWuk94WCrrwslk8yWNGmY1EduTA=="
    crossorigin="anonymous"
    referrerpolicy="no-referrer"
  />
    <link rel="stylesheet" href="css/style.css">
</head>
<body>

css href 경로는 server.js 에서 이미 prefix해서 css/style.css 만 적기 

 

=> localhost:3000 가면 css 적용된 ejs render 되어 있음

 

 

12. New User 클릭 -> add user form 

views > add_user.ejs 파일 생성 

index.ejs 의 include header & footer 코드 복붙 

add_user.ejs에 add_user.html 의 main site 부분 전체 복사 , header & footer 사이에 붙여넣기 

add_user.ejs에 복붙한 main site 중 form handling을 파일로 또 빼기 

add_user.ejs

<!-- include header -->
<%- include('include/_header.ejs')%>
<!-- /include header -->


    <!-- Main site -->
    <main id="site-main">
        <div class="container">
          <div class="box-nav d-flex justify-between">
              <div class="filter">
                  <a href="/"><i class="fas fa-angle-double-left"></i>All Users</a>
              </div>
          </div>
          <div class="form-title text-center">
              <h2 class="text-dark">
                  New User
              </h2>
              <span class="text-light">
                  Use the below form to create a new account
              </span>
          </div>
  
          <!-- add user form  -->
          <%- include('include/_form.ejs')%>

        </div>
      </main>
      <!-- /Main site -->

<!-- include footer -->
<%- include('include/_footer.ejs')%>
<!-- /include footer -->

 

server.js /add_user 추가 

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

app.get('/add-user', (req,res)=>{
    res.render('add_user');
})

 

index.ejs 의 New User <a tag> 에 이미 href="add-user" 적어놓음 

=> localhost:3000 -> New User 클릭 -> New User (add_user.ejs) render 됨 

All Users 돌아가기 버튼 눌르면 '/' 로 돌아가짐! 

 

 

 

 

13. Update (User 정보 수정) 

views > update_user.ejs 생성 & add_user.ejs 코드 복붙 & 일부 수정 (form handling부분 다시 가져와서 복붙! ) 

update_user.ejs

<!-- include header -->
<%- include('include/_header.ejs')%>
<!-- /include header -->

<!-- Main site -->
<main id="site-main">
  <div class="container">
    <div class="box-nav d-flex justify-between">
      <div class="filter">
        <a href="/"><i class="fas fa-angle-double-left"></i>All Users</a>
      </div>
    </div>
    <div class="form-title text-center">
      <h2 class="text-dark">Update User</h2>
      <span class="text-light"> Use the below form to update an account </span>
    </div>

    <!-- add user form  -->
    <!-- form handling-->
    <form method="POST" id="update_user">
      <div class="new_user">
        <div class="form-group">
          <label for="name" class="text-light">Name</label>
          <input type="hidden" name="id" value="" />
          <input type="text" name="name" value="" placeholder="Name" />
        </div>
        <div class="form-group">
          <label for="Email" class="text-light">Email</label>
          <input
            type="text"
            name="email"
            value=""
            placeholder="example@gmail.com"
          />
        </div>
        <div class="form-group">
          <label for="gender" class="text-light">Gender</label>
          <div class="radio inline">
            <input type="radio" id="radio-2" name="gender" value="Male" />
            <label for="radio-2" class="radio-label">Male</label>
          </div>
          <div class="radio inline">
            <input type="radio" id="radio-3" name="gender" value="Female" />
            <label for="radio-3" class="radio-label">Female</label>
          </div>
        </div>
        <div class="form-group">
          <label for="gender" class="text-light">Status</label>
          <div class="radio inline">
            <input type="radio" id="radio-4" name="status" value="Active" />
            <label for="radio-4" class="radio-label">Active</label>
          </div>
          <div class="radio inline">
            <input type="radio" id="radio-5" name="status" value="Inactive" />
            <label for="radio-5" class="radio-label">Inactive</label>
          </div>
        </div>
        <div class="form-group">
          <button type="submit" class="btn text-dark update">Save</button>
        </div>
      </div>
    </form>
  </div>
</main>
<!-- /Main site -->

<!-- include footer -->
<%- include('include/_footer.ejs')%>
<!-- /include footer -->

_form.ejs 에 form id = update_user -> add_user로 변경 

          <!-- form handling-->
          <form method="POST" id="add_user">
            <div class="new_user">
                <div class="form-group">

_show.ejs <a hre="#"> -> "/update-user" 로 변경 

<tr>
  <td>1</td>
  <td>Username</td>
  <td>exameple@gmail.com</td>
  <td>Female</td>
  <td>Active</td>
  <td>
    <a href="/update-user" class="btn border-shadow update">
      <span class="text-gradient"><i class="fas fa-pencil-alt"></i></span>
    </a>
    <a class="btn border-shadow delete">
      <span class="text-gradient"><i class="fas fa-times"></i></span>
    </a>
  </td>
</tr>

server.js '/update-user' 추가 

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

app.get('/add-user', (req,res)=>{
    res.render('add_user');
})

app.get('/update-user', (req,res)=>{
    res.render('update_user');
})

편집 icon을 누르면 Update User page가 뜸 ! (Add USer 와 형식 똑같음) 

=> 이제 html 파일들(index.html, add_user.html) 삭제해도 좋음! 

 

 

 

 

 

 14. Routes 

MONGODB_CRUD > server > routes 폴더 생성 > router.js 파일 생성

server.js 에서 app.get 부분 복사 -> router.js 붙여넣기 + expresss, route 가져오기 + app -> route로 수정 + export 

 

router.js

const express = require('express');
// const app = express(); app을 또 사용 X 
const route = express.Router();

route.get('/', (req,res)=>{
    res.render('index');
})

route.get('/add-user', (req,res)=>{
    res.render('add_user');
})

route.get('/update-user', (req,res)=>{
    res.render('update_user');
})


module.exports = route

server.js

.
.
.

// load assets
app.use('/css', express.static(path.resolve(__dirname, "assets/css")));
app.use('/img', express.static(path.resolve(__dirname, "assets/img")));
app.use('/js', express.static(path.resolve(__dirname, "assets/js")));

//load routers
app.use('/', require('./server/routes/router'));

app.listen(PORT, ()=>{
    console.log(`Server is running on http://localhost:${PORT}`)
})

이렇게 router 사용할 때 보통 변수로 위의 router를 가져왔는데 여기에선 변수로 담지않고 그냥 바로 사용함 

 

 

 

 

 

15. router에 callback function 따로 빼기

MONGODB_CRUD > server > services 폴더 생성 > render.js 폴더 생성 + 코드 작성

exports.homeRoutes = (req,res)=>{
    res.render('index');
}

router.js  

const express = require('express');
// const app = express(); app을 또 사용 X 
const route = express.Router();

const services = require('../services/render')

route.get('/', services.homeRoutes)

route.get('/add-user', (req,res)=>{
    res.render('add_user');
})

route.get('/update-user', (req,res)=>{
    res.render('update_user');
})


module.exports = route

나머지도 바꾸기 

render.js

exports.homeRoutes = (req,res)=>{
    res.render('index');
}

exports.add_user = (req,res)=>{
    res.render('add_user');
}

exports.update_user = (req,res)=>{
    res.render('update_user');
}

router.js

const express = require('express');
// const app = express(); app을 또 사용 X 
const route = express.Router();

const services = require('../services/render')

/**
* @description Root Route
* @method GET /
*/
route.get('/', services.homeRoutes)

/**
* @description add users
* @method GET /add-user
*/
route.get('/add-user', services.add_user)

/**
* @description for update users
* @method GET /update-user
*/
route.get('/update-user', services.update_user)


module.exports = route

 

 

 

 

16. MongoDB 

https://www.mongodb.com/

 

The most popular database for modern apps

We're the creators of MongoDB, the most popular database for modern apps, and MongoDB Atlas, the global cloud database on AWS, Azure, and GCP. Easily organize, use, and enrich data — in real time, anywhere.

www.mongodb.com

local / cloud 중 큰 프로젝트는 cloud 사용하는게 더 좋다고 함 ! local의 경우 모든 데이터를 잃을 수도 있다고... 

 

 

아래 순서대로 이제 진행하기 ! 

 

 

1) build your cluster 

- 구글 로그인 -> new project -> project 이름 설정 -> create -> 해당명으로 project생성됨 

- Build a Database 클릭 -> 무료버전 선택 -> aws, singapore 선택 -> 확인 -> cluster 생성 완료 

 

2) Create your database user

왼쪽 Security - Database Access -> Add New Database User 클릭

 

 

 

 

3) Add IP Address to your Access List

왼쪽 메뉴 - Security - Network Access -> Add IP Address -> allow access from anywhere 클릭

It alows me to access to this database from any localhost 

 

 

왼쪽 메뉴 Databases - Connect 클릭 -> Connect your application 선택 -> copy your application code 

 

 

 

 

MongoDB my application과 연결하기 

Connect to your cluster 

vsc 로 돌아가서 MONGODB_CURD > config.env 파일 코드 추가 

PORT=3000
MONGO_URI=mongodb+srv://admin:<아까 입력한 user password>@cluster0.loh1o.mongodb.net/<데이터베이스 이름>?retryWrites=true&w=majority

 

MONGODB_CRUD > server > database 폴더 > connection.js 파일 생성 & 코드 작성

const mongoose = require('mongoose');
const connectDB = async()=>{
    try{
        // mongoDB connection string 
        const con = await mongoose.connect(process.env.MONGO_URI,{
            useNewUrlParser:true,
            useUnifiedTopology:true,
            // useFindAndModify:false,
            // useCreateIndex:true
        });

        console.log(`MongoDB connected : ${con.connection.host}`)
    }catch(err){
        console.log(err.message);
        process.exit(1); // 1==true
    }
}

module.exports=connectDB;

* 위 두 옵션은 더이상 안쓴다고 함..

https://stackoverflow.com/questions/68958221/mongoparseerror-options-usecreateindex-usefindandmodify-are-not-supported

 

MongoParseError: options useCreateIndex, useFindAndModify are not supported

I tried to run it and it said an error like the title. and this is my code: const URI = process.env.MONGODB_URL; mongoose.connect(URI, { useCreatendex: true, useFindAndModify: false,

stackoverflow.com

server.js

const connectDB = require('./server/database/connection');

// log requests
app.use(morgan("tiny"));

// mongoDB connection
connectDB();

연결됐다~~~~~~~~~

 

 

 

 

17. API 

MONGODB_CRUD > server > model > model.js 파일 생성 + 코드 작성

* schema allows you to define a shape and content of the document 

const mongoose = require('mongoose');

let schema = new mongoose.Schema({
    name:{
        type:String,
        required:true
    },
    email:{
        type:String,
        require:true,
        unique:true
    },
    gender:String,
    status:String
})

const Userdb = mongoose.model('userdb', schema);

module.exports=Userdb;

MONGODB_CRUD > server > controller > controller.js 파일 생성 + 코드 작성

let Userdb = require('../model/model');

// create and save new user 
exports.create = (req,res)=>{

}

// retrieve and return all users / retreive and return a single user
exports.find = (req,res)=>{

}

// update a new identified user by userid 
exports.update = (req,res)=>{

}

// delete a user with specified userid in the request 
exports.delete = (req,res)=>{

}

server > routes > router.js 

const controller = require('../controller/controller')

.
.
.

//API
route.post('/api/users', controller.create);
route.get('/api/users', controller.find);
route.put('/api/users/:id', controller.update);
route.delete('/api/users/:id', controller.delete);

 

mongoDB와 주고받기 

  CREATE    

server > controller > controller.js 

exports.create = (req,res)=>{
    //validate request / body에 아무것도 없는 경우 예외처리 
    if(!req.body){
        res.status(400).send({message:'Content can not be empty!'});
        return;
    }
    
    // new user / create an instance 
    const user = new Userdb({
        name:req.body.name,
        email:req.body.email,
        gender:req.body.gender,
        status:req.body.status
    })

    // save user(the instance made above) in the DB 
    user
      .save(user)
      .then(data=>{
          res.send(data)
      })
      .catch(err=>{
          res.status(500).send({
              message:err.message || "Some error occurred while creating a create operation"
          })
      })
}

create postman 으로 test 해보기 

mongoDB - database - collection 확인해보기 

데이터가 잘 들어와 있다 !

 

users - 데이타베이스 이름

userdbs - document 이름 

 

 

  FIND (SELECT)   

controller.js 

exports.find 부분 수정 

find() 모든 data return (지금 1개밖에 없어서 하나만 출력) 

// retrieve and return all users / retreive and return a single user
exports.find = (req,res)=>{
    Userdb.find()
    .then(user =>{
        res.send(user)
    })
    .catch(err=>{
        res.status(500).send({
            message:err.message || "Error Occurred while retrieving user information"
        })
    })
}

postman으로 test 

 

Get Single User 

여러 데이터들 중 특정 1user 만 find / get 해오기 

postman 으로 데이터 몇개 더 create 해주기 

// retrieve and return all users / retreive and return a single user
exports.find = (req,res)=>{

    if(req.query.id){
        const id = req.query.id;

        Userdb.findById(id)
            .then(data=>{
                if(!data){
                    res.status(404).send({
                        message:`Not found user with ${id}`
                    })
                }else{
                    res.send(data)
                }
            })
            .catch(err=>{
                res.status(500).send({
                    message:`error retrieving user with ${id}`
                })
            })
    }else{
        Userdb.find()
        .then(user =>{
            res.send(user)
        })
        .catch(err=>{
            res.status(500).send({
                message:err.message || "Error Occurred while retrieving user information"
            })
        })
    }
}

postman 

params로 id 적으면 해당 id data만 return 

 

 

  UPDATE   

controller.js 

// update a new identified user by userid 
exports.update = (req,res)=>{
    if(!req.body){
        return res
            .status(400)
            .send({
                message:"Data to update can not be empty"
            })
    }

    const id = req.params.id;
    Userdb.findByIdAndUpdate(id,req.body,{useFindAndModify:false})
        .then(data=>{
            if(!data){
                res.status(404).send({
                    message : `Cannot update user with ${id}. Maybe user not found`
                })
            }else{
                res.send(data)
            }
        })
        .catch(err=>{
            res.status(500).send({
                message:'Error update user information'
            })
        })
}

postman

*  url 뒤에 id 꼭 붙이기! 

원래 actice 였던 상태가 inactive로 update 됨 ! 

 

mongoDB 도 변경되어 있음 

 

 

 

  DELETE   

controller.js

exports.delete = (req,res)=>{
    const id = req.params.id;

    Userdb.findByIdAndDelete(id)
        .then(data=>{
            if(!data){
                res.status(404).send({
                    message: `Cannot delete with id ${id}.`
                })
            }else{
                res.send({
                    message:`User was deleted successfully!`
                })
            }
        })
        .catch(err=>{
            res.status(500).send({
                message:`Coule not delete User with id = ${id}`
            });
        });
}

postman test 

mongoDB - 하나 있던 data 삭제됨 

 

 

 

 

18. Using API 

application main page에 mongoDB에 있는 모든 데이터 distribute 뿌리기 

render.js

exports.homeRoutes = (req,res)=>{
    res.render('index', {users:'New Data'});
}

index.ejs

              </thead>
              <tbody>
                  <!-- table  -->
                <%- include('include/_show.ejs')%>
              </tbody>
            </table>
          </form>
          <%=users%>                // 추가 
        </div>
      </main>

그럼 user라는 변수에 들어간 'New Data' 라는 값이 나온다 (서커 껏다가 켜주기) 

요렇게

이런 식으로 mongoDB에서 가져온 모든 data를 index.ejs에 뿌려보기 

 

render.js 

axios로 데이터 가져오기 - promise로 반환

const axios = require('axios');

exports.homeRoutes = (req,res)=>{
    
    // make a get request to /api/users
    axios.get('http://localhost:3000/api/users')
        .then(function(response){
            console.log(`response.data:`,response.data)
            res.render('index', {users:response.data});
        })
        .catch(err=>{
            res.send(err);
        })

}

index.ejs 

뿌릴 테이블은 _show.ejs에 들어가 있다. 이전에 적은 코드( <%=users%>) 삭제 / 원상복귀하기

              <tbody>
                  <!-- table  -->
                <%- include('include/_show.ejs')%>
              </tbody>
            </table>
          </form>
        </div>
      </main>

views > include > _show.ejs 

users 라는 변수로 받은 내용을 for문으로 뿌리기 

<% for(let i=0; i<users.length; i++){%>
<tr>
  <td><%=i+1%></td>
  <td><%=users[i].name%></td>
  <td><%=users[i].email%></td>
  <td><%=users[i].gender%></td>
  <td><%=users[i].status%></td>
  <td>
    <a href="/update-user" class="btn border-shadow update">
      <span class="text-gradient"><i class="fas fa-pencil-alt"></i></span>
    </a>
    <a class="btn border-shadow delete">
      <span class="text-gradient"><i class="fas fa-times"></i></span>
    </a>
  </td>
</tr>
<%}%>

html의 <% %>요 문법과 ejs 문법이 좀 다름 ! 잘 보기 

 

 

 

19. Create New User 

_form.ejs 

action 추가 

            <!-- form handling-->
            <form action="/api/users" method="POST" id="add_user">
                <div class="new_user">
                    <div class="form-group">

controller.js  - create 부분

    // save user(the instance made above) in the DB 
    user
      .save(user)
      .then(data=>{
          //res.send(data)
          res.redirect('/')       // redirect로 수정 
      })
      .catch(err=>{
          res.status(500).send({
              message:err.message || "Some error occurred while creating a create operation"
          })
      })
}

까지만 하고 add user 해보면 add한 ㅎㄷㄷ user가 잘 들어와있다! 

여기서 jQuery로 user 성공적으로 생성되었따고 alert주기 

 

google "jqueyr cdnjs" 검색 아래 들어가서 가장 위의 코드 복사 

https://cdnjs.com/libraries/jquery

 

jquery - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers

JavaScript library for DOM operations - Simple. Fast. Reliable. Content delivery at its finest. cdnjs is a free and open-source CDN service trusted by over 12.5% of all websites, serving over 200 billion requests each month, powered by Cloudflare. We make

cdnjs.com

 

views > include > _footer.ejs 

jquery script 넣고 커스텀 js위한 script 추가 

<!-- jquery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- custom js file -->
<script src="js/index.js"></script>

</body>
</html>

MONGODB > assets > js > index.js 생성

server.js에서 이미 경로 저장해놓아서 js/index.js 로만 써도 된다. ↓↓

app.use('/js', express.static(path.resolve(__dirname, "assets/js")));

asstes > js > index.js 


$('#add_user').submit(function(event){
    alert('Data Inserted Successfully!')
})

처음써보는 jQuery........ 

 

이제 add new user하면 alert가 뜬다!

그리고 redirected well!

 

 

 

 

20. Update User

먼저 편집icon클릭 -> add_user.ejs 로 넘어갈 때 기존 user의 정보 불러오기 

render.js

exports.update_user = (req,res)=>{
    // let id = req.query.id;
    // axios.get(`http://localhost:3000/api/users?id=${id}`)
    axios.get('http://localhost:3000/api/users', {params:{id:req.query.id}})
        .then(function(user_data){
            console.log(`user_data.data=`, user_data.data)
            res.render('update_user', {user:user_data.data})
        })
        .catch(err=>{
            res.send(err);
        })
}

 

_show.ejs  - id pass하기

.
.
.
  <td>
    <a href="/update-user?id=<%=users[i]._id%>" class="btn border-shadow update">
.
.
.

update_user.ejs 


        <div class="form-group">
          <label for="name" class="text-light">Name</label>
          <input type="hidden" name="id" value="<%=user._id%>" />
          <input type="text" name="name" value="<%=user.name%>" placeholder="emily" />
        </div>
        <div class="form-group">
          <label for="Email" class="text-light">Email</label>
          <input type="text" name="email" value="<%=user.email%>" placeholder="test@test.com" />
        </div>
        <div class="form-group">
          <label for="gender" class="text-light">Gender</label>
          <div class="radio inline">
            <input type="radio" id="radio-2" name="gender" value="Male" >
            <label for="radio-2" class="radio-label">Male</label>
          </div>
          <div class="radio inline">
            <input type="radio" id="radio-3" name="gender" value="Female">
            <label for="radio-3" class="radio-label">Female</label>
          </div>
        </div>
        <div class="form-group">
          <label for="gender" class="text-light">Status</label>
          <div class="radio inline">
            <input type="radio" id="radio-4" name="status" value="Active">
            <label for="radio-4" class="radio-label">Active</label>
          </div>
          <div class="radio inline">
            <input type="radio" id="radio-5" name="status" value="Inactive" >
            <label for="radio-5" class="radio-label">Inactive</label>
          </div>
        </div>
        <div class="form-group">

gender 와 status는 아래처럼 하면되는데 내 코드는 빨간색으로 나오면서 에러가 난다 ! 일단 요 부분 제외하고 넘어가기 

 

assets > js > index.js 

$('#update_user').submit(function(event){
    event.preventDefault();

    // 아래에서 this는 '#update_user'와 같음 
    let unindexed_array = $(this).serializeArray();
    console.log('upindexed arrya=',unindexed_array)
})

update_user.ejs 에서 submit을 눌렀을 때 막기 & console.log 찍기 

jquery에서 serializeArray()는 form 에서 <input name="" value=""> 를 객체 직렬화 함

출처 : https://m.blog.naver.com/wiseyoun07/220659439860

 

data 라는 {} 객체 만들어서 위의 내용 name 와 value 넣기 

$('#update_user').submit(function(event){
    event.preventDefault();

    // 아래에서 this는 '#update_user'와 같음 
    let unindexed_array = $(this).serializeArray();
    let data = {}
    $.map(unindexed_array,function(n,i){
        data[n['name']]=n['value']
    })

    console.log('upindexed array=',unindexed_array)
    console.log(data)
})

이제 data 안의 id를 얻어서 put API로 보내기 

$('#update_user').submit(function(event){
    event.preventDefault();

    // 아래에서 this는 '#update_user'와 같음 
    let unindexed_array = $(this).serializeArray();
    let data = {}
    $.map(unindexed_array,function(n,i){
        data[n['name']]=n['value']
    })

    console.log('upindexed array=',unindexed_array);
    console.log(data);

    let request = {
        'url':`http://localhost:3000/api/users/${data.id}`,
        'method':'PUT',
        'data':data,
    }

    $.ajax(request).done(function(response){
        alert('Data updated successfully!')
    })

})

-> 수정이 되고 메인 페이지에도 적용된다! 

 

 

21. Delete User 

_show.ejs

data-id 추가 

    </a>
    <a class="btn border-shadow delete" data-id=<%=users[i]._id%>>
      <span class="text-gradient"><i class="fas fa-times"></i></span>
    </a>

assets > js > index.js

if(window.location.pathname=='/'){
    $ondelete = $('.table tbody td a.delete');
    $ondelete.click(function(){
        let id = $(this).attr('data-id')

        let request = {
            'url':`http://localhost:3000/api/users/${id}`,
            'method':'DELETE'
        }

        if(confirm("Do you really want to delete this record?")){
            $.ajax(request).done(function(response){
                alert('Data deleted successfully!');
                location.reload();
            })
        }
    })
}

 

삭제하기까지 완성! 

 

전체 코드 : https://github.com/ohse-emily/CRUD_application_with_nodejs_mongoDB

 

GitHub - ohse-emily/CRUD_application_with_nodejs_mongoDB

Contribute to ohse-emily/CRUD_application_with_nodejs_mongoDB development by creating an account on GitHub.

github.com

 

 

 


 

Reference : https://www.youtube.com/watch?v=W1Kttu53qTg 

 

반응형