λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
[개발] Practice/Node.js MongoDB

[Node.js / MongoDB] νšŒμ› κΈ°λŠ₯을 ν¬ν•¨ν•œ κ²Œμ‹œνŒ κΈ°λŠ₯ λ§Œλ“€κΈ°

by Connecting-the-dots 2022. 3. 15.
728x90
λ°˜μ‘ν˜•

πŸ’‘ μ‹€μŠ΅ 포인트!

πŸ’œ νšŒμ›κ°€μž… κΈ°λŠ₯ λ§Œλ“€κΈ°

  • 이전에 κ±΄λ„ˆλ›΄ νšŒμ›κ°€μž… κΈ°λŠ₯을 λ§Œλ“€μ–΄ μ‚¬μš©μžλ₯Ό μΆ”κ°€ν•΄λ³΄μ•˜λ‹€.
    (쀑볡 아이디 확인 κΈ°λŠ₯은 μΆ”ν›„ λ§Œλ“€ μ˜ˆμ •)

πŸ’œ κ²Œμ‹œλ¬Ό μž‘μ„±μžλ§Œ κ²Œμ‹œλ¬Ό μ‚­μ œ κΆŒν•œ μ£ΌκΈ°

  • λ‘œκ·ΈμΈν•œ μ‚¬μš©μžλ§Œ 본인의 κ²Œμ‹œκΈ€μ„ μ‚­μ œν•  수 μžˆλŠ” κΈ°λŠ₯을 λ§Œλ“€μ–΄λ³΄μ•˜λ‹€.
    (λ‘œκ·ΈμΈν•˜μ§€ μ•Šκ³  κ²Œμ‹œλ¬Ό λ“±λ‘ν•˜λŠ” 경우 였λ₯˜κ°€ λ°œμƒν•˜λŠ” 뢀뢄은 μΆ”ν›„ μˆ˜μ • μ˜ˆμ •)

πŸ’œ νšŒμ›κ°€μž… κΈ°λŠ₯ λ§Œλ“€κΈ°

🀍 νšŒμ›κ°€μž… EJS 파일 λ§Œλ“€κΈ°

<h4 class="container mt-5"><strong>νšŒμ›κ°€μž…</strong></h4>
<div class="container mt-4">
  <form action="/register" method="POST">
    <div class="form-group my-4">
      <label class="mb-2">아이디</label>
      <input type="text" class="form-control" name="id">
    </div>
    <div class="form-group my-4">
      <label class="mb-2">λΉ„λ°€λ²ˆν˜Έ</label>
      <input type="password" class="form-control" name="pw">
    </div>
    <button type="submit" class="btn btn-danger fw-bold">νšŒμ›κ°€μž…</button>
  </form>
</div>
  • κ°•μ‚¬λ‹˜μ€ λΉ λ₯Έ μˆ˜μ—…μ„ μœ„ν•΄ 둜그인 νŽ˜μ΄μ§€μ— νšŒμ›κ°€μž… λ ˆμ΄μ•„μ›ƒμ„ μΆ”κ°€ μž‘μ„±ν•˜μ…¨λŠ”λ°, λ‚˜λŠ” νšŒμ›κ°€μž… νŽ˜μ΄μ§€λ₯Ό λ”°λ‘œ λ§Œλ“€μ—ˆλ‹€. (μ—­μ‹œ νšŒμ›κ°€μž… νŽ˜μ΄μ§€μ™€ 둜그인 νŽ˜μ΄μ§€λŠ” 뢄리해주어야 마음이 νŽΈμ•ˆν•˜λ‹€.)
  • λ ˆμ΄μ•„μ›ƒ μžμ²΄λŠ” 둜그인 νŽ˜μ΄μ§€μ™€ λ™μΌν•˜κ²Œ ν•˜κ³  λ‚΄μš©κ³Ό action μ†μ„±λ§Œ μˆ˜μ •ν•΄μ£Όμ—ˆλ‹€.

🀍 νšŒμ›κ°€μž… κΈ°λŠ₯ κ΄€λ ¨ JavaScript μ½”λ“œ μž‘μ„±ν•˜κΈ°

app.get('/register', function(req, res){
    res.render('register.ejs');
})

app.post('/register', function(req, res){
    db.collection('login').insertOne({id : req.body.id, pw: req.body.pw}, function(err, result){
        res.redirect('/login');
    })
})
  • 일단, λˆ„κ΅°κ°€κ°€ /register 경둜둜 GET μš”μ²­μ„ ν•˜λ©΄ νšŒμ›κ°€μž… νŽ˜μ΄μ§€κ°€ 보이도둝 ν•΄μ£Όμ—ˆλ‹€.
  • κ·Έ λ‹€μŒμœΌλ‘œ λˆ„κ΅°κ°€κ°€ 폼을 μž‘μ„±ν•œ 후에 νšŒμ›κ°€μž… λ²„νŠΌμ„ ν΄λ¦­ν•˜λ©΄ μž‘μ„±ν•œ 아이디와 λΉ„λ°€λ²ˆν˜Έλ₯Ό db.collection 의 login 에 μΆ”κ°€ν•˜κ³  둜그인 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•˜κ²Œλ” μ„€μ •ν•΄μ£Όμ—ˆλ‹€.
  • κ°„μ΄λ‘œ λ§Œλ“  ν˜•μ‹μ΄λ―€λ‘œ ꡉμž₯히 κ°„μ†Œν™”λ˜μ—ˆμ§€λ§Œ μ‹€μ§ˆμ μœΌλ‘œ 이 νšŒμ›κ°€μž… κΈ°λŠ₯을 κ΅¬ν˜„ν•  λ•Œμ—λŠ” 생각해봐야할 뢀뢄듀이 κ½€ μžˆλ‹€.
    • νšŒμ›κ°€μž…ν•˜λ €κ³  ν•˜λŠ” 아이디가 이미 DB 에 μ‘΄μž¬ν•˜λŠ” 아이디인지 ν™•μΈν•œλ‹€. (아이디 쀑볡 확인)
    • νšŒμ›κ°€μž…ν•˜λ €κ³  ν•˜λŠ” 아이디가 아이디 생성 양식을 잘 지킀고 μžˆλŠ”μ§€ ν™•μΈν•œλ‹€.
    • λΉ„λ°€λ²ˆν˜Έλ₯Ό DB 에 μ „μ†‘ν•˜κΈ° 전에 μ•”ν˜Έν™”λ₯Ό ν–ˆλŠ”μ§€ ν™•μΈν•œλ‹€. (λ³΄μ•ˆ 문제 방지)

πŸ’œ κ²Œμ‹œλ¬Ό μž‘μ„±μžλ§Œ μ‚­μ œ κΆŒν•œ μ£ΌκΈ°

🀍 κ²Œμ‹œλ¬Ό 등둝할 λ•Œ, κ²Œμ‹œλ¬Ό μž‘μ„±μž 정보 λ„£κΈ°

// λˆ„κ΅°κ°€κ°€ νΌμ—μ„œ /add 둜 POST μš”μ²­μ„ ν•˜λ©΄
app.post('/add', function(req, res){

    // κ²Œμ‹œλ¬Όλ§ˆλ‹€ 번호λ₯Ό 달아 μ €μž₯ν•˜κΈ°
    // DB.counter λ‚΄μ—μ„œ 'μ΄κ²Œμ‹œλ¬Όκ°œμˆ˜'λ₯Ό μ°Ύμ•„μ„œ
    db.collection('counter').findOne({name : 'μ΄κ²Œμ‹œλ¬Όκ°œμˆ˜'}, function(err, result){
        // console.log(result.totalPosts);

        // 'μ΄κ²Œμ‹œλ¬Όκ°œμˆ˜' 의 totalPosts 값을 totalPosts λ³€μˆ˜μ— μ €μž₯
        var totalPosts = result.totalPosts;

        // 전솑받아 μ €μž₯ν•  데이터듀을 submitData λ³€μˆ˜μ— μ €μž₯
        var submitData = {
            _id : totalPosts + 1, 
            할일: req.body.content, 
            마감일 : req.body.date, 
            μž‘μ„±μž: req.user._id
        }

        // 이제 DB.post 에 번호λ₯Ό 단 μƒˆλ‘œμš΄ κ²Œμ‹œλ¬Όμ„ μΆ”κ°€
        db.collection('post').insertOne(submitData, function(err, result){
            console.log('κ²Œμ‹œλ¬Ό μ €μž₯ μ™„λ£Œ!');

            // DB.counter 의 'μ΄κ²Œμ‹œλ¬Όκ°œμˆ˜' 의 totalPosts 값을 1μ”© 증가
            db.collection('counter').updateOne({name : 'μ΄κ²Œμ‹œλ¬Όκ°œμˆ˜'},{ $inc : {totalPosts: 1} }, function(err, result){
                console.log('총 κ²Œμ‹œλ¬Ό 개수 μ—…λ°μ΄νŠΈ μ™„λ£Œ!');
            });
        });
    });

    // res.send('κ²Œμ‹œλ¬Ό μΆ”κ°€ μ™„λ£Œ');
    res.redirect('/list') 
})
  • 기쑴에 μž‘μ„±ν–ˆλ˜ μ½”λ“œμ˜ 경우, κ²Œμ‹œλ¬Όμ„ μž‘μ„± ν›„ λ“±λ‘ν•˜λ©΄ _id, 할일, 마감일 λ§Œ DB 둜 μ „μ†‘λ˜λ„λ‘ κ΅¬ν˜„ν–ˆμ—ˆκΈ°μ— μž‘μ„±μžλŠ” μ•Œ 수 μ—†μ—ˆλ‹€.
  • λ”°λΌμ„œ, κ²Œμ‹œλ¬Όμ„ 등둝할 λ•Œ μž‘μ„±μž λ₯Ό μΆ”κ°€ν•΄μ€ŒμœΌλ‘œμ„œ κ²Œμ‹œλ¬Ό μž‘μ„±μžλ₯Ό ꡬ별할 수 μžˆλ„λ‘ ν•˜μ˜€λ‹€.
  • μ£Όμ˜ν•  점은 req.user κ΄€λ ¨ 정보듀을 deserializeUser() ν•¨μˆ˜κ°€ μ œκ³΅ν•˜λ―€λ‘œ passport κ΄€λ ¨ μ½”λ“œλ“€λ³΄λ‹€ μ•„λž˜μͺ½μœΌλ‘œ μ½”λ“œλ₯Ό μ΄λ™μ‹œμΌœμ£Όμ–΄μ•Ό ν•œλ‹€. 
  • μœ„ μ½”λ“œμ—μ„œλŠ” μ½”λ“œμ˜ 가독성을 μœ„ν•΄ submitData λΌλŠ” λ³€μˆ˜μ— 전솑받아 DB 에 μ €μž₯ν•  데이터듀을 λ‹΄μ•„μ€€ ν›„, ν•΄λ‹Ή λ³€μˆ˜λ‘œ 기쑴의 μ½”λ“œλ₯Ό μˆ˜μ •ν•΄μ£Όμ—ˆλ‹€.

  • 이제 κ²Œμ‹œλ¬Όμ„ μƒˆλ‘œ λ“±λ‘ν•˜λ©΄ μž‘μ„±μž 정보도 post collection 에 μ €μž₯λ˜λŠ” 것을 λ³Ό 수 μžˆλ‹€.

🀍 κ²Œμ‹œλ¬Ό μž‘μ„±μžλ§Œ κ²Œμ‹œκΈ€ μ‚­μ œν•˜λŠ” κΆŒν•œ μ£ΌκΈ°

// λˆ„κ΅°κ°€κ°€ μ‚­μ œ λ²„νŠΌμ„ ν΄λ¦­ν•˜μ—¬ /delete 둜 DELETE μš”μ²­μ„ ν•˜λ©΄
app.delete('/delete', function(req, res){
    // DB μ—μ„œ κ²Œμ‹œκΈ€ μ‚­μ œν•˜κΈ°
    req.body._id = parseInt(req.body._id);

    var delData = {_id : req.body._id, μž‘μ„±μž : req.user._id}
    
    db.collection('post').deleteOne(delData, function(err, result){
        console.log('κ²Œμ‹œλ¬Ό μ‚­μ œ μ™„λ£Œ');
        res.status(200).send({message : 'μ„±κ³΅ν–ˆμŠ΅λ‹ˆλ‹€.'});
    })
})
  • 기쑴의 μ½”λ“œλŠ” post collection μ—μ„œ _id 에 ν•΄λ‹Ήν•˜λŠ” κ²Œμ‹œλ¬Όλ§Œμ„ μ°Ύμ•„ μ‚­μ œλ₯Ό μ§„ν–‰ν–ˆλ‹€.
  • μ΄λ²ˆμ—λŠ” κ²Œμ‹œλ¬Ό μž‘μ„±μžλ§Œ κ²Œμ‹œκΈ€μ„ μ‚­μ œν•  수 μžˆμ–΄μ•Ό ν–ˆκΈ°μ—, λ‘œκ·ΈμΈν•œ μ‚¬μš©μžκ°€ req.user._id 에 담겨 μžˆλŠ” μƒνƒœμ—μ„œ μ‚­μ œν•˜λ €λŠ” κ²Œμ‹œλ¬Όμ˜ μž‘μ„±μžκ°€ req.user._id 의 쑰건을 λ§Œμ‘±ν•˜λ©΄ κ²Œμ‹œλ¬Όμ΄ μ‚­μ œλ˜λ„λ‘ ν•΄μ£Όμ—ˆλ‹€.

🀍 μ• λ‹ˆλ©”μ΄μ…˜ 효과 문제 처리λ₯Ό μœ„ν•΄ μ½”λ“œ μˆ˜μ •ν•˜κΈ°

  • 근데 μ—¬κΈ°κΉŒμ§€λ§Œ ν–ˆμ„ λ•Œ 생각지 λͺ»ν•œ λ¬Έμ œκ°€ λ°œμƒν–ˆλ‹€.
  • λ°”λ‘œ μ‚­μ œ λ²„νŠΌμ„ λˆ„λ₯΄κΈ°λ§Œ 해도 μ‹€μ œλ‘œ 데이터가 μ‚­μ œλ˜λ“  μ•„λ‹ˆλ“  μ‚­μ œλ˜μ–΄λ³΄μ΄λŠ” 이전에 μ„€μ •ν•΄λ‘” μ• λ‹ˆλ©”μ΄μ…˜ νš¨κ³Όκ°€ λ‚˜νƒ€λ‚˜λŠ” 것이닀.
  • κ°•μ˜μ—μ„œλŠ” κ±΄λ„ˆλ›΄ 뢀뢄이라 이 뢀뢄은 슀슀둜 ν•΄κ²°ν•  방법을 μ°Ύμ•„μ•Ό ν–ˆκ³ , μ—­μœΌλ‘œ μΆ”μ ν•˜λ©΄μ„œ μ „λ°˜μ μœΌλ‘œ μˆ˜μ •μ„ ν•˜λŠλΌ μ‹œκ°„μ΄ μ’€ κ±Έλ Έλ‹€.
  • 일단 이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•œ λ‚΄ 생각은 μ΄λŸ¬ν–ˆλ‹€.
    • 할일 리슀트 νŽ˜μ΄μ§€μ—μ„œ μ‚­μ œ λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ κ²Œμ‹œλ¬Όμ˜ _id 와 ν•¨κ»˜ μž‘μ„±μž 데이터λ₯Ό /delete 경둜둜 μ „μ†‘ν•œλ‹€.
    • μ „μ†‘λœ κ²Œμ‹œλ¬Ό λ°μ΄ν„°μ˜ _id 와 μž‘μ„±μž 뢀뢄을 λ°›μ•„μ˜¨λ‹€.
    • κ²Œμ‹œλ¬Ό λ°μ΄ν„°μ˜ μž‘μ„±μžμ™€ ν˜„μž¬ μ‚¬μš©μžμ˜ _id λ₯Ό λΉ„κ΅ν•œλ‹€.
    • λ§Œμ•½ 두 데이터가 μΌμΉ˜ν•˜λ©΄, κ²Œμ‹œλ¬Ό _id λ₯Ό κ²€μƒ‰ν•˜μ—¬ μ‚­μ œν•œ ν›„ μ„±κ³΅μ½”λ“œ 200 을 μ „μ†‘ν•˜κ³ , μΌμΉ˜ν•˜μ§€ μ•ŠμœΌλ©΄ μ‹€νŒ¨μ½”λ“œ 400 을 μ „μ†‘ν•œλ‹€.
    • EJS 파일이 μ„±κ³΅μ½”λ“œλ₯Ό μ „λ‹¬λ°›μœΌλ©΄ κ²Œμ‹œλ¬Όμ— fadeOut 효과λ₯Ό μ£Όκ³ , μ‹€νŒ¨μ½”λ“œλ₯Ό μ „λ‹¬λ°›μœΌλ©΄ μ•„λ¬΄λŸ° νš¨κ³Όκ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€.
<h4 class="container mt-5 mb-4"><strong>할일 리슀트</strong></h4>

<div class="container input-group mb-1">
  <input class="form-control" id="search-input">
  <button class="input-group-append btn btn-danger" id="search">검색</button>
</div>

<div class="container mt-3">
  <ul class="list-group">
    <% for(let i = 0; i < post.length; i++){ %>
    <li class="list-group-item mb-2" style="border-top-width: 1px">
      <p class="mb-2" style="font-size: 14px;">κΈ€λ²ˆν˜Έ : <%= post[i]._id %></p>
      <p class="mb-2" style="font-size: 18px;">할일 : <%= post[i].할일 %></p>
      <p class="mb-2" style="font-size: 16px;">마감일 : <%= post[i].마감일 %></p>
      <button class="btn btn-primary edit"><a style="color: white; text-decoration: none;" href="/edit/<%= post[i]._id %>">μˆ˜μ •</a></button>
      <button class="btn btn-danger delete" data-id="<%= post[i]._id %>" data-writer="<%= post[i].μž‘μ„±μž %>">μ‚­μ œ</button>
    </li>
    <% } %>
  </ul>
</div>
  • 이전에 κΈ€μ“°κΈ° νŽ˜μ΄μ§€μ—μ„œ Submit λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ κ²Œμ‹œλ¬Όμ˜ _id 와 ν•¨κ»˜ μž‘μ„±μžμ˜ 정보도 DB 둜 μ „μ†‘λ˜μ–΄ μ €μž₯λ˜μ–΄μ•Ό ν–ˆλ‹€.
  • κ·Έλž˜μ„œ html μ½”λ“œ λΆ€λΆ„μ˜ button νƒœκ·Έμ— data-writer λ₯Ό μΆ”κ°€ν•΄μ£Όμ—ˆλ‹€. 
  $('.delete').click(function(e){

    let postNum = e.target.dataset.id;
    let writer = e.target.dataset.writer;
    let clicked = $(this);

    $.ajax({
      method : 'DELETE',
      url : '/delete',
      data : {_id : postNum, μž‘μ„±μž : writer}
    }).done(function(result){
      // AJAX 성곡할 경우 μ‹€ν–‰ν•  μ½”λ“œ
      console.log('μ„±κ³΅ν–ˆμŠ΅λ‹ˆλ‹€.');
      clicked.parent('li').fadeOut();
    }).fail(function(err){
      // AJAX μ‹€νŒ¨ν•  경우 μ‹€ν–‰ν•  μ½”λ“œ
      console.log('μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.');
    })

  })
  • 기쑴에 data-id 만 λ°›μ•˜λ‹€λ©΄, μ‚­μ œ λ²„νŠΌμ— μΆ”κ°€ν•΄λ‘” data-writer 도 λ°›μ•„μ™€μ„œ /delete 경둜둜 전솑 μ‹œ data 객체에 λ‹΄μ•„ 같이 μ „μ†‘ν•΄μ£Όμ—ˆλ‹€.
// λˆ„κ΅°κ°€κ°€ μ‚­μ œ λ²„νŠΌμ„ ν΄λ¦­ν•˜μ—¬ /delete 둜 DELETE μš”μ²­μ„ ν•˜λ©΄
app.delete('/delete', function(req, res){
    // DB μ—μ„œ κ²Œμ‹œκΈ€ μ‚­μ œν•˜κΈ°
    req.body._id = parseInt(req.body._id);

    var delData = {_id : req.body._id}

    console.log(req.body);

    if (req.body.μž‘μ„±μž == req.user._id) {
        db.collection('post').deleteOne(delData, function(err, result){
            console.log('κ²Œμ‹œλ¬Ό μ‚­μ œ μ™„λ£Œ');
            res.status(200).send({message : 'μ„±κ³΅ν–ˆμŠ΅λ‹ˆλ‹€.'});
        })
    } else {
        console.log('κ²Œμ‹œλ¬Ό μ‚­μ œ μ‹€νŒ¨');
        res.status(400).send({message : 'μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.'});
    }
})
  • 기쑴에 console.log(req.body) λ₯Ό ν•΄λ³΄μ•˜μ„ λ•Œ _id 만 좜λ ₯λ˜μ—ˆλ˜ 반면, μ΄μ œλŠ” _id 와 μž‘μ„±μžκ°€ 좜λ ₯λœλ‹€.
  • 이제 이것을 ν™œμš©ν•΄μ„œ req.body.μž‘μ„±μž(κ²Œμ‹œλ¬Ό μž‘μ„±μž) 와 req.user._id(ν˜„μž¬ λ‘œκ·ΈμΈν•œ μ‚¬μš©μž) λ₯Ό 비ꡐ할 수 있게 λ˜μ—ˆλ‹€.
  • 두 데이터λ₯Ό λΉ„κ΅ν–ˆμ„ λ•Œ μΌμΉ˜ν•œλ‹€λ©΄ ν˜„μž¬ λ‘œκ·ΈμΈν•œ μ‚¬μš©μžκ°€ κ²Œμ‹œλ¬Ό μž‘μ„±μžλ‹ˆκΉŒ ν•΄λ‹Ή κ²Œμ‹œλ¬Όμ˜ _id λ₯Ό λ°›μ•„μ™€μ„œ 데이터λ₯Ό μ‚­μ œν•œλ‹€.
    • μ‚­μ œν•˜κ³ λ‚˜μ„œλŠ” 'κ²Œμ‹œλ¬Ό μ‚­μ œ μ™„λ£Œ' λΌλŠ” 문ꡬλ₯Ό λ„μ›Œ μ œλŒ€λ‘œ μ‚­μ œλ˜μ—ˆλŠ”μ§€ ν™•μΈν•œλ‹€.
    • res.status(200).send() κΉŒμ§€ ν•΄μ£Όλ©΄ 할일 리슀트 EJS 파일의 .done() ν•¨μˆ˜ λ‚΄μ˜ fadeOut() ν•¨μˆ˜κ°€ μ‹€ν–‰λœλ‹€.
  • 두 데이터λ₯Ό λΉ„κ΅ν–ˆμ„ λ•Œ μΌμΉ˜ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ ν˜„μž¬ λ‘œκ·ΈμΈν•œ μ‚¬μš©μžκ°€ κ²Œμ‹œλ¬Ό μž‘μ„±μžκ°€ μ•„λ‹ˆλΌλŠ” μ΄μ•ΌκΈ°μ΄λ―€λ‘œ κ²Œμ‹œλ¬Όμ΄ μ‚­μ œλ˜μ–΄μ„œλŠ” μ•ˆλœλ‹€.
    • λ”°λΌμ„œ, 'κ²Œμ‹œλ¬Ό μ‚­μ œ μ‹€νŒ¨' λΌλŠ” 문ꡬλ₯Ό λ„μ›Œμ€€λ‹€.
    • res.status(400).send() λ₯Ό ν•΄μ£Όμ–΄ 할일 리슀트 EJS 파일의 .fail() ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜μ–΄ μ• λ‹ˆλ©”μ΄μ…˜ νš¨κ³ΌλŠ” λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€. 

 

 

 

728x90
λ°˜μ‘ν˜•