KDT/TIL

9/7 TIL : form ํƒœ๊ทธ๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ, fetch, MongoDB

ebulsok 2022. 9. 18. 20:41

๐Ÿ”Ž ์ถ”๊ฐ€ routing ์ฒ˜๋ฆฌ

app.js์— ์ฝ”๋“œ ์ถ”๊ฐ€

const router = require('./routes/index');

app.use('/', router);

/routes/index.js ์ƒ์„ฑ

// @ts-check
const express = require('express');

const router = express.Router();

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

module.exports = router;

/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>Index</title>
</head>

<body>
  <h1>Hello, Express Service</h1>
  <h2><a href="/users">Move to USER service</a></h2>
  <h2><a href="/posts">Move to POST service</a></h2>
</body>

</html>

 

๐Ÿ”Ž res.status(undefined) ์—๋Ÿฌ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด app.js์—์„œ ์—๋Ÿฌ์ฝ”๋“œ ์ˆ˜์ •

์–ด๋””์„œ ๋ฐœ์ƒํ•œ ๊ฒƒ์ธ์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ์„œ๋ฒ„์ƒ์˜ ๋ฌธ์ œ์ด๋ฏ€๋กœ err ๊ฐ์ฒด์— statusCode๊ฐ€ ์—†์œผ๋ฉด 500์„ ๋„์šฐ๋„๋ก ํ•จ

(ex. ejs ํŒŒ์ผ์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ)

app.use((err, req, res, next) => {
  console.log(err.stack);
  res.status(err.statusCode || 500);
  res.send(err.message);
});

 

๐Ÿ”Ž ํ”„๋ก ํŠธ์˜ form ํƒœ๊ทธ๋กœ ๋ฐฑ์— ๋ฐ์ดํ„ฐ ๋ณด๋‚ด๊ธฐ

๐Ÿšฉ Form

  • action : ๋ณด๋‚ด๊ณ ์ž ํ•˜๋Š” ์ฃผ์†Œ ๊ฐ’
  • method : ๋ณด๋‚ด๋Š” method ์„ค์ •
  • input์˜ name : ์„œ๋ฒ„์—์„œ ๋ฐ›์„ ๋•Œ์˜ ํ•„๋“œ ๊ฐ’
  • button์œผ๋กœ submit์„ ํ•˜๋ฉด ํ•ด๋‹น ํผ์˜ ๋‚ด์šฉ์„ ์ง€์ •ํ•œ ๋ฐฉ์‹ + ์ฃผ์†Œ๋กœ ์ „๋‹ฌํ•จ
<form action="/users" method="POST">
    <div>
      <label>ID</label>
      <input type="text" name="id" />
    </div>
    <div>
      <label>NAME</label>
      <input type="text" name="name" />
    </div>
    <div>
      <label>EMAIL</label>
      <input type="email" name="email" />
    </div>
    <button type="submit">Submit</button>
 </form>

 

๐Ÿšฉ body-parser: form์—์„œ ์ „์†ก๋œ ์ •๋ณด๋ฅผ req.body์— ๋‹ด์•„์„œ obj๋กœ ์ „๋‹ฌํ•ด์ฃผ๋Š” ์—ญํ• 

์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ body์— ๋„ฃ์€ ๋‹ค์Œ ์ธ์ฝ”๋”ฉ ์ฒ˜๋ฆฌ๊นŒ์ง€ ํ•ด์ค˜์•ผ ํ•จ

(req.on('data', function(chunk) { body += chunk; });)

  • [ํ„ฐ๋ฏธ๋„] npm install body-parser --save
  • app.js์— ์ฝ”๋“œ ์ถ”๊ฐ€
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
  • url-encoded ์˜ต์…˜์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€ํ™˜ํ•˜๋ฉด ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ json ํ˜•ํƒœ๋ผ๊ณ  ์ „๋‹ฌ
  • extended: true => query๋กœ ๋“ค์–ด์˜จ ๋ฌธ์ž์—ด์„ ์™ธ๋ถ€ ๋ชจ๋“ˆ์ธ qs ๋ชจ๋“ˆ๋กœ ์ฒ˜๋ฆฌ(์„ค์น˜ ํ•„์š”, npm i qs)
  • extended: false => express ๋‚ด์žฅ ๋ชจ๋“ˆ์ธ queryString ๋ชจ๋“ˆ๋กœ ์ฒ˜๋ฆฌ, ์ค‘์ฒฉ๋œ ๊ฐ์ฒด ํ—ˆ์šฉ x

 

๐Ÿšฉ req.body ์ฒ˜๋ฆฌ

  • form์—์„œ ์ „๋‹ฌ๋œ ์ •๋ณด๋Š” req.body๋ฅผ ํ†ตํ•ด ๋“ค์–ด์˜ด
  • req.query ๊ฐ’์€ ์ „๋‹ฌํ•˜์ง€ ์•Š์•„๋„ ๋นˆ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋Š”๋ฐ ๋นˆ ๊ฐ์ฒด๋Š” if๋ฌธ์—์„œ true๋ฅผ ๋ฆฌํ„ดํ•˜๋ฏ€๋กœ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ•„์š”
  • ํšŒ์›๊ฐ€์ž…์ด ์™„๋ฃŒ๋˜๋ฉด ๋‹ค์‹œ ํšŒ์› ๋ชฉ๋ก ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋„๋ก res.direct ์‚ฌ์šฉ
router.post('/', (req, res) => {
  if (Object.keys(req.query).length > 0) {
    if (req.query.id && req.query.name && req.query.email) {
      const newUser = {
        id: req.query.id,
        name: req.query.name,
        email: req.query.email,
      };
      USER.push(newUser);
      res.redirect('/users');
    } else {
      const err = new Error('Unexpected query');
      err.statusCode = 404;
      throw err;
    }
  } else if (req.body) {
    if (req.body.id && req.body.name && req.body.email) {
      const newUser = {
        id: req.body.id,
        name: req.body.name,
        email: req.body.email,
      };
      USER.push(newUser);
      res.redirect('/users');
    } else {
      const err = new Error('Unexpected form Data');
      err.statusCode = 404;
      throw err;
    }
  } else {
    const err = new Error('No data');
    err.statusCode = 404;
    throw err;
  }
});

 

๐Ÿ”Ž form ์—†์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•

๐Ÿšฉ XMLHttpRequest

  • 1999๋…„์— ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„ ์ธก ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•ด ํƒ„์ƒ
  • promise ๋“ฑ์„ ๊ธฐ๋ณธ์œผ๋กœ ๋‚ด์žฅํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„ ํ†ต์‹ ์„ ๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ๋”ฐ๋กœ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š” ๋ถˆํŽธํ•จ์ด ์žˆ์Œ

 

๐Ÿšฉ JQuery

  • 2006๋…„ ๋“ฑ์žฅํ•˜์—ฌ DOM ๊ธฐ๋Šฅ, ๋ฐ์ดํ„ฐ ํ†ต์‹  ๋“ฑ ๋‹ค์–‘ํ•œ ๋ถ„์•ผ์—์„œ ์‚ฌ์šฉ
  • ES6 ๋ฌธ๋ฒ•์ด ๋“ฑ์žฅํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์ฃผ๋กœ JQuery๋ฅผ ํ†ตํ•ด ํ†ต์‹ 

 

๐Ÿšฉ Fetch()

  • ๋ธŒ๋ผ์šฐ์ €์—์„œ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ํ†ต์‹ ์„ ์œ„ํ•ด 2015๋…„ ES6์—์„œ ์ถ”๊ฐ€๋œ ๊ธฐ๋Šฅ
  • ๊ธฐ์กด์˜ XMLHttpRequest์˜ ๋ฌธ์ œ์ ์„ ๊ฐœ์„ ํ•˜์—ฌ(promise ๋‚ด์žฅ) ์„œ๋ฒ„ ํ†ต์‹  ์ฝ”๋“œ๋ฅผ ๋ฐฑ์—”๋“œ ์ฝ”๋“œ์™€ ๋น„์Šทํ•˜๊ฒŒ ์งค ์ˆ˜ ์žˆ์Œ

 

๐Ÿšฉ fetch๋ฅผ ์ด์šฉํ•œ ์‚ญ์ œ ๊ธฐ๋Šฅ ๊ตฌํ˜„

  • li ์š”์†Œ์— ์‚ญ์ œ ๋ฒ„ํŠผ ์ถ”๊ฐ€(a ํƒœ๊ทธ)
  • a ํƒœ๊ทธ์— onclick์œผ๋กœ ์‚ญ์ œ ํ•จ์ˆ˜ ์—ฐ๊ฒฐ => ํ•ด๋‹น ํ•จ์ˆ˜์—์„œ fetch๋กœ ์‚ญ์ œ api ์š”์ฒญ
<li>
      <p>id: <%= USER[i].id %></p>
      <p>name: <%= USER[i].name %></p>
      <p>email: <%= USER[i].email %></p>
      <a href="" onclick="deleteUser('<%= USER[i].id %>');">์‚ญ์ œ</a>
</li>
  • deleteUser(id) ํ•จ์ˆ˜ ๊ตฌํ˜„
<script>
  function deleteUser(id) {
    fetch(`http://localhost:4000/users/${id}`, {
      method: 'delete',
      headers: {
        'Content-type': 'application/json'
      },
    }).then((res) => {
      location.reload();
    })
  }
</script>

 

๐Ÿ”Ž DBMS(DataBase Managemanet System): ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์šด์˜ํ•˜๋Š” SW

๐Ÿšฉ SQL(Structured Query Language): select, insert, update, delete ๊ฐ™์€ ์–ธ์–ด๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ์–ธ์–ด

 

๐Ÿšฉ ๊ด€๊ณ„ํ˜•(SQL), Relational DBMS(RDBMS): SQL์„ ์‚ฌ์šฉํ•˜๋Š” DB, ํ‚ค์™€ ๊ฐ’์˜ ๊ด€๊ณ„๋ฅผ ํ…Œ์ด๋ธ”ํ™” ์‹œํ‚จ ์›์น™์„ ํ† ๋Œ€๋กœ ๊ตฌ์„ฑ

  • ๋จผ์ € ํ…Œ์ด๋ธ”์ด ๊ตฌ์„ฑ๋˜๊ณ  ํ…Œ์ด๋ธ”์˜ ๊ตฌ์กฐ์— ๋งž์ถ”์–ด ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— DB๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ ์ „์— ์Šคํ‚ค๋งˆ๋ผ ๋ถˆ๋ฆฌ๋Š” DB์˜ ๊ตฌ์กฐ, ๊ด€๊ณ„, ์ œ์•ฝ ์‚ฌํ•ญ์— ๋Œ€ํ•œ ์ •์˜๊ฐ€ ํ•„์š”
  • ์žฅ์ : ๊ตฌ์กฐํ™”๊ฐ€ ๋ช…ํ™•ํ•ด์„œ ์˜ˆ์™ธ๊ฒŒ ์—†์Œ, ๋ฐ์ดํ„ฐ ์ž…์ถœ๋ ฅ ์†๋„๊ฐ€ ๋น ๋ฆ„, ์‹ ๋ขฐ์„ฑ์ด ๋†’์Œ
  • ๋‹จ์ : DB์˜ ๊ตฌ์กฐ ๋ณ€๊ฒฝ์ด ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์— ๋น…๋ฐ์ดํ„ฐ ๋“ฑ์€ ์‚ฌ์šฉ์ด ์–ด๋ ค์›€(์ƒˆ๋กœ์šด ํ‚ค๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ์ „์ฒด ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์ด ํ•„์š”)

 

๐Ÿšฉ ๋น„๊ด€๊ณ„ํ˜•(NoSQL): SQL์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ชจ๋“  DB

  • ๋ฌธ์„œํ˜•, ๊ทธ๋ž˜ํ”„ํ˜•, ํ‚ค๋ฐธ๋ฅ˜ํ˜•, ์™€์ด๋“œ ์ปฌ๋Ÿผํ˜•...
  • ํŠน์ • ๋ชฉ์ ์— ๋งž๋Š” DB๊ฐ€ ์กด์žฌ
  • ์žฅ์ : ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์— ํšจ์œจ์ , ๊ตฌ์กฐ ๋ณ€๊ฒฝ์ด ์‰ฝ๊ณ  ํ™•์žฅ์„ฑ์ด ๋›ฐ์–ด๋‚จ, ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์˜ ํ‘œํ˜„์ด ๊ฐ€๋Šฅ
  • ๋‹จ์ : ๋ฐ์ดํ„ฐ ์ž์ฒด๊ฐ€ ํฌ๋ฉด ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ์ผ๋ถ€ ์ฝ์–ด์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ํฌ๋ฉด ์†๋„๊ฐ€ ์ €ํ•˜๋˜๋Š” ๋ฌธ์ œ ๋ฐœ์ƒ

 

๐Ÿšฉ MongoDB(Humongous DB)

  • ์žฅ์ : ๋ฐ์ดํ„ฐ๋ฅผ ์ต์ˆ™ํ•œ JSON ํ˜•ํƒœ๋กœ ์ฒ˜๋ฆฌ, ๊ตฌ์กฐ ๋ณ€๊ฒฝ ์šฉ์ด, ๋†’์€ ์ˆ˜ํ‰ ํ™•์žฅ์„ฑ, ์Šคํ‚ค๋งˆ ์„ค๊ณ„์˜ ์œ ์—ฐ์„ฑ
  • ๋‹จ์ : ํ‘œ์ค€์ด ์—†์Œ, ๋ฐ์ดํ„ฐ๊ฐ€ ๊ตฌ์กฐํ™” ๋˜์–ด ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์ˆœํ•œ ๊ตฌ์กฐ์˜ ์ฟผ๋ฆฌ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ณ  ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ ๋ฐ ์•ˆ์ •์„ฑ์„ DB๊ฐ€ ์•„๋‹Œ App ๋ ˆ๋ฒจ์—์„œ ๊ด€๋ฆฌํ•ด์ค˜์•ผ ํ•จ => ๋ฒ„๊ทธ ๋ฐœ์ƒ ํ™•๋ฅ  ๋†’์Œ
  • https://www.mongodb.com/ko-kr/cloud/atlas/efficiency ์—์„œ ๋กœ๊ทธ์ธ -> FREE db -> cluster ์ƒ์„ฑ -> username/password -> ip ๋“ฑ๋ก -> connect -> include full driver code example ์ฒดํฌ ํ›„ ์ฝ”๋“œ ๋ณต์‚ฌ
  • routes/mongo.js ์ƒ์„ฑ ํ›„ ๋ถ™์—ฌ๋„ฃ๊ธฐ
  • [ํ„ฐ๋ฏธ๋„] npm i mongodb
  • [ํ„ฐ๋ฏธ๋„] node routes/mongo.js
  • mongodb ์ ‘์†์šฉ ํ•จ์ˆ˜ + ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒ์„ฑ(async, await)
// @ts-check
const { MongoClient, ServerApiVersion } = require('mongodb');

const uri =
  'mongodb+srv://ebulsok:<password>@cluster0.dvpqw9g.mongodb.net/?retryWrites=true&w=majority';
const client = new MongoClient(uri, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  serverApi: ServerApiVersion.v1,
});

async function main() {
  await client.connect();

  const users = client.db('KDT-1').collection('users');

  await client.close();
}

main();

 

.insertOne({ }) : ํ•˜๋‚˜์˜ ๋„ํ๋จผํŠธ(๋ฐ์ดํ„ฐ) ์‚ฝ์ž…

.insertMany([{ }]) : ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ๊บผ๋ฒˆ์— ์‚ฝ์ž…(๋ฐฐ์—ด์— ๋‹ด๊ธด ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ์ „๋‹ฌ ๋˜์–ด์•ผ ํ•จ)

 

.deleteOne({ }) : ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ฒซ ๋„ํ๋จผํŠธ ํ•˜๋‚˜๋ฅผ ์‚ญ์ œ

.deleteMany([{ }]) : ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ๊บผ๋ฒˆ์— ์‚ญ์ œ

 

.updateOne({ }, { $set: { }, }) : ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ฒซ ๋„ํ๋จผํŠธ ํ•˜๋‚˜๋ฅผ ์ˆ˜์ •

.updateMany({ }, { $set: { }, }) : ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ชจ๋“  ๋„ํ๋จผํŠธ๋ฅผ ์ˆ˜์ •

 

.findOne({ }) : ๊ฒ€์ƒ‰ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ฒซ ๋„ํ๋จผํŠธ๋ฅผ ์ฐพ์•„์„œ ๊ฐ’์„ ๋ฐ˜ํ™˜(๋ณ€์ˆ˜์— ๋„ฃ์–ด์„œ ์ฒ˜๋ฆฌ/๋ฐ”๋กœ ์ถœ๋ ฅํ•ด์•ผํ•จ)

.find([{ }]) : ์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋ถ€ ์ฐพ์•„์คŒ

  • ์‹ค์ œ์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ๋ณด๋‹ค cursor ๊ฐ์ฒด๋กœ ์ €์žฅ
  • ๋ฆฌํ„ด์ด ๋  ๋•Œ await๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ
  • find๋กœ ์ฐพ์€ ๊ฐ’์„ ์ถœ๋ ฅํ•˜๋ ค๋ฉด await์™€ ํ•จ๊ป˜ forEach() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•จ
  • ๋ฐ์ดํ„ฐ๋กœ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด await์™€ ํ•จ๊ป˜ toArray() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉ

๋น„๊ต์‹/๋…ผ๋ฆฌ์‹

// db.์ปฌ๋ ‰์…˜๋ช….find({์ฟผ๋ฆฌ: [{์กฐ๊ฑด1}, {์กฐ๊ฑด2}, ...]});

const data = users.find({
    $and: [{ age: { $gte: 5 } }, { name: 'loopy' }],
 });
 await data.forEach(console.log);