Node.js์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ์— ์ธ๋ฑ์Šค ๋ถ™์ด๊ธฐ, ๋ฐ์ดํ„ฐ ์‚ญ์ œํ•˜๊ธฐ 4

๐Ÿ™‹โ€โ™‚๏ธ1. Node.js๋กœ 5๋ถ„๋งŒ์— API ๋งŒ๋“ค๊ธฐ
๐Ÿ™‹โ€โ™‚๏ธ2. Node.js๋กœ POST API ๋งŒ๋“ค๊ธฐ
๐Ÿ™‹โ€โ™‚๏ธ3. Node.js๋กœ ๋ฐ์ดํ„ฐ ์ €์žฅํ•˜๊ธฐ
MongoDB์—๋Š” id๋ฅผ Auto Increment ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์—†๋‹ค. ๊ฒŒ์‹œํŒ์˜ ๊ธ€๋ฒˆํ˜ธ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค๋ ค๋ฉด ๋”ฐ๋กœ ๊ตฌํ˜„์ด ํ•„์š”ํ•œ๋ฐ, ์ด๋ฒˆ์— ์–ด๋–ป๊ฒŒ ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์ž. ๊ทธ๋ฆฌ๊ณ  ๊ฒŒ์‹œ๋ฌผ์„ ์‚ญ์ œํ•˜๋Š” ๊ฒƒ๊นŒ์ง€ ํ•ด ๋ณผ ์ƒ๊ฐ์ด๋‹ค(Update, Delete).

MongoDB์— collection ํ•˜๋‚˜ ๋” ๋งŒ๋“ค๊ธฐ

mongoDB ์šฐ์„  ๊ธฐ์กด์— ๋งŒ๋“ค์–ด๋†“์€ post ์ปฌ๋ ‰์…˜ ์™ธ์— counter ์ปฌ๋ ‰์…˜์„ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค๊ณ , ๋‚ด๋ถ€์— ์ž„์˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜ ๋„ฃ์–ด๋ณด์ž. totalPost ํ•ญ๋ชฉ์€ int32๋กœ ์„ค์ •ํ•ด์ค€๋‹ค. ์ด์ œ totalPost์— ์ง€๊ธˆ๊นŒ์ง€ ๋ช‡ ๋ฒˆ ๊ฒŒ์‹œ๋ฌผ์„ ๋ฐœํ–‰ํ–ˆ๋Š”์ง€ ์ €์žฅํ•  ์˜ˆ์ •์ด๋‹ค.

๊ตฌํ˜„ํ•  ๋‚ด์šฉ์˜ ํ๋ฆ„์„ ์ •๋ฆฌํ•ด๋ณด์ž๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  1. ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ฒŒ์‹œ๋ฌผ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญ
  2. counter์—์„œ ํ˜„์žฌ ๊ฒŒ์‹œ๋ฌผ ์ด ๊ฐœ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ
  3. ์ด ๊ฐœ์ˆ˜ + 1๋กœ ์ƒˆ๋กœ์šด ๊ฒŒ์‹œ๋ฌผ์˜ _id ๋งŒ๋“ค๊ธฐ
  4. post์— ์ €์žฅ
  5. counter์˜ totalPost๊ฐ’ +1๋กœ ์—…๋ฐ์ดํŠธ
  6. ์ €์žฅ ์™„๋ฃŒ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜

๊ธฐ์กด ์ฝ”๋“œ ์ˆ˜์ •ํ•˜๊ธฐ

์›๋ž˜๋Š” ์ด๋Ÿฐ ์‹์œผ๋กœ ๊ตฌํ˜„ ๋˜์–ด ์žˆ์—ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
app.post('/add', async (req, res) => {
    try {
        const data = req.body; // ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์Œ
        await db.collection('post').insertOne(data);
        console.log('โœ… ๋ฐ์ดํ„ฐ ์ €์žฅ ์™„๋ฃŒ:', data);
        res.send("๋ฐ์ดํ„ฐ ์ €์žฅ ์™„๋ฃŒ!");
    } catch (error) {
        console.error("โŒ ๋ฐ์ดํ„ฐ ์ €์žฅ ์‹คํŒจ:", error);
        res.status(500).send("๋ฐ์ดํ„ฐ ์ €์žฅ ์‹คํŒจ!");
    }
}); 

์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€๊ฒฝํ•ด๋ณด์ž.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

app.post('/add', async (req, res) => {
    const session = db.client.startSession();

    try {
        const data = req.body; // ์š”์ฒญ์œผ๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ
        await session.withTransaction(async () => {
            // 1. ๊ฒŒ์‹œ๋ฌผ ๊ฐฏ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ
            const counterCollection = db.collection('counter');
            const counter = await counterCollection.findOne({ name: '๊ฒŒ์‹œ๋ฌผ๊ฐฏ์ˆ˜' }, { session });

            if (!counter) {
                throw new Error("์นด์šดํ„ฐ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.");
            }

            const ์ด๊ฒŒ์‹œ๋ฌผ๊ฐฏ์ˆ˜ = counter.totalPost;

            // 2. post ์ €์žฅ (๊ฒŒ์‹œ๋ฌผ ๋ฒˆํ˜ธ = ์ด๊ฒŒ์‹œ๋ฌผ๊ฐฏ์ˆ˜ + 1)
            const newPost = {
                _id: ์ด๊ฒŒ์‹œ๋ฌผ๊ฐฏ์ˆ˜ + 1,
                title: data.title,
                content: data.content
            };

            await db.collection('post').insertOne(newPost, { session });
            console.log('โœ… ์ƒˆ ๊ฒŒ์‹œ๋ฌผ ์ €์žฅ ์™„๋ฃŒ:', newPost);

            // 3. counter ์—…๋ฐ์ดํŠธ (totalPost + 1)
            await counterCollection.updateOne(
                { name: '๊ฒŒ์‹œ๋ฌผ๊ฐฏ์ˆ˜' },
                { $inc: { totalPost: 1 } },
                { session }
            );

            console.log('โœ… ๊ฒŒ์‹œ๋ฌผ ๊ฐฏ์ˆ˜ ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ');
        });

        res.send("๋ฐ์ดํ„ฐ ์ €์žฅ ์™„๋ฃŒ!");
    } catch (error) {
        console.error("โŒ ๋ฐ์ดํ„ฐ ์ €์žฅ ์‹คํŒจ:", error);
        res.status(500).send("๋ฐ์ดํ„ฐ ์ €์žฅ ์‹คํŒจ!");
    } finally {
        await session.endSession();
    }
}); 

์ฝ”๋“œ๊ฐ€ ๋งŽ์ด ๊ธธ์–ด์ง„ ๊ฒƒ ๊ฐ™์ง€๋งŒ ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ๋งŒ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๊ฒŒ์‹œ๋ฌผ ์ €์žฅ๊ณผ ์นด์šดํ„ฐ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด withTransaction์„ ์‚ฌ์šฉํ•ด์„œ ์•ˆ์ •์„ฑ์„ ํ™•๋ณดํ•˜๋Š๋ผ ์ฝ”๋“œ๊ฐ€ ์ข€ ๋” ๊ธธ์–ด์กŒ๋‹ค. counter์— ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•ด์„œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ธฐ๋„ ํ–ˆ๋‹ค. ๊ฒŒ์‹œ๋ฌผ ์ €์žฅ ์ค‘์— ์„œ๋ฒ„๊ฐ€ ๊บผ์ง€๊ฑฐ๋‚˜ ํ•˜๋Š” ๊ฒฝ์šฐ์— ๊ฒŒ์‹œ๋ฌผ ์ˆ˜๊ฐ€ ์ข€ ์–ด๊ธ‹๋‚˜๋„ ์ƒ๊ด€์—†๋‹ค๋ฉด ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š์•„๋„ ๋ฌธ์ œ๋Š” ์—†๋‹ค.

๊ฒฐ๊ณผ๋ณด๊ธฐ
์ด์ œ ๊ฒŒ์‹œ๋ฌผ ๋ฒˆํ˜ธ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด์„œ ๊ธฐ์กด totalPost๋ฅผ Update ํ•˜๋Š” ๊ฒƒ๊นŒ์ง€ ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค.

๊ฒŒ์‹œ๋ฌผ ์‚ญ์ œ๋ฅผ ํ•ด๋ณด์ž

HTTP ์š”์ฒญ์—๋Š” 4๊ฐ€์ง€ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋‹ค. GET, POST, PUT, DELETE์ธ๋ฐ form์—์„œ๋Š” GET, POST ์š”์ฒญ๋ฐ–์— ํ•  ์ˆ˜ ์—†๋‹ค. ๊ทธ๋Ÿผ ์‚ญ์ œ ์š”์ฒญ์€ ์–ด๋–ป๊ฒŒ ๋ณด๋‚ด์•ผ ํ• ๊นŒ?

  1. AJAX๋กœ DELETE ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.
  2. POST ์š”์ฒญ์„ ๋‚ ๋ ค์„œ DELETE๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

์‚ฌ์‹ค ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ๋ชจ๋‘ ์ž‘๋™ํ•˜๊ณ , POST๋กœ ์‚ญ์ œ ์š”์ฒญ์„ ๋ณด๋‚ด๋„ ์ƒ๊ด€์€ ์—†์ง€๋งŒ! Restfulํ•œ API๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์กฐ๊ธˆ ๋” ๋ฒˆ๊ฑฐ๋กญ๋”๋ผ๋„ 1๋ฒˆ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script>
        $.ajax({
          method : 'DELETE',
          url : '/delete',
          data : '1๋ฒˆ๊ฒŒ์‹œ๋ฌผ'
        }).done(function(๊ฒฐ๊ณผ){
          AJAX ์„ฑ๊ณต์‹œ ์‹คํ–‰ํ•  ์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ
        }).fail(function(์—๋Ÿฌ){
          ์‹คํŒจ์‹œ ์‹คํ–‰ํ•  ์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ
        });
      </script>

AJAX์˜ ๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ๋ฒ•์€ ์œ„์™€ ๊ฐ™๋‹ค. Jquery๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ์“ธ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์šฐ์„ ์€ ๋น ๋ฅด๊ณ  ํŽธํ•˜๊ฒŒ ์“ฐ๊ธฐ ์œ„ํ•ด jquery ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ์œ„ ์˜ˆ์‹œ๋ฅผ ์‹ค์ œ ์ฝ”๋“œ์— ์ ์šฉํ•ด๋ณด์ž.

1
2
3
4
5
6
7
8
9
<ul class="list-group">
    <% posts.forEach(function(post) { %>
        <li class="list-group-item">
            <h4><%= post.title %></h4> 
            <p><%= post.content %></p>
            <button type="button" data-id="<%= post._id %>" class="btn btn-secondary delete">Delete</button>
        </li>
    <% }); %>
</ul>

button์— data-id๋ฅผ ๋ถ™์—ฌ์„œ ๊ฐ ํ•ญ๋ชฉ์˜ _id๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋„๋ก ํ•ด ๋‘” ๋‹ค์Œ,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
    $('.delete').click(function(){ 
        const button = $(this); // ํ˜„์žฌ ํด๋ฆญํ•œ ๋ฒ„ํŠผ
        const postId = button.data('id'); // ํด๋ฆญํ•œ ๋ฒ„ํŠผ์˜ data-id ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ

        $.ajax({
            method: 'DELETE',
            url: '/delete',
            data: { _id: postId } // _id์— ์‹ค์ œ ๊ฒŒ์‹œ๋ฌผ ID ์ „์†ก
        }).done(function(result){
            alert('์‚ญ์ œ ์™„๋ฃŒ!');
            button.closest('li').fadeOut(); // ํด๋ฆญํ•œ ๋ฒ„ํŠผ์ด ์†ํ•œ li ์š”์†Œ ์‚ญ์ œ. fadeOut() ๋Œ€์‹  remove()๋„ ๊ฐ€๋Šฅ 
        }).fail(function(err) {
            alert('์‚ญ์ œ ์‹คํŒจ!');
            console.error('โŒ ์‚ญ์ œ ์š”์ฒญ ์‹คํŒจ:', err);
        });

    });
</script>

๊ฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ AJAX๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ์ฒ˜๋ฆฌํ•œ๋‹ค.

1
2
3
4
5
6
7
app.delete('/delete', function(req, res){
    req.body._id = parseInt(req.body._id)
    db.collection('post').deleteOne(req.body, function(error, result){
        console.log('์‚ญ์ œ์™„๋ฃŒ')
      })
    res.send('์‚ญ์ œ์™„๋ฃŒ')
  });

server.js์—๋„ /delete์š”์ฒญ์ด ๋“ค์–ด์™”์„ ๋•Œ ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•  ์ง€ ์ž‘์„ฑ์ด ํ•„์š”ํ•˜๋‹ค. id๊ฐ’์„ ์ˆซ์ž๋กœ ์ฐพ์„ ์ˆ˜ ์žˆ๋„๋ก request์—์„œ ๋ฐ›์€ _id๋ฅผ parseInt ํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•˜๋‹ค.

AJAX Delete ์š”์ฒญ์€ ์‚ฌ์‹ค

1
2
3
4
$.ajax({
     method: 'DELETE',
     url: '/delete/1',
})

์ด๋Ÿฐ ์‹์œผ๋กœ, data๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š๊ณ  url์— ๋ฐ”๋กœ ๋‹ด์•„์„œ ์ „๋‹ฌํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋” ์ผ๋ฐ˜์ ์ด๋‹ค. ์œ„์—์„œ๋Š” AJAX์‚ฌ์šฉ๋ฒ•์— ์ตœ๋Œ€ํ•œ ๋งž์ถ”์–ด์„œ ์ž‘์„ฑํ•ด๋ณด๋ ค๊ณ  data์— ๋‹ด์•˜๋‹ค.

์‘๋‹ต ๋ฐ์ดํ„ฐ์˜ ์ข…๋ฅ˜ ์•Œ์•„๋ณด๊ธฐ

1
2
3
4
5
6
7
app.get('/๊ฒฝ๋กœ', function(์š”์ฒญ, ์‘๋‹ต){
  ์‘๋‹ต.send('<p>ํŽ˜์ด์ง€ ๋ณด๊ธฐ</p>')
  ์‘๋‹ต.status(404).send('ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค')
  ์‘๋‹ต.sendFile('/uploads/ok.png')
  ์‘๋‹ต.render('list.ejs', { ejs์— ๋ณด๋‚ผ ๋ฐ์ดํ„ฐ })
  ์‘๋‹ต.json(json๋ฐ์ดํ„ฐ)
});
  • send : ๊ฐ„๋‹จํ•œ ๋ฌธ์ž, html ์ฝ”๋“œ๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
  • status : ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
  • sendFile : static ํŒŒ์ผ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
  • render : ejs๋“ฑ์˜ ํ…œํ”Œ๋ฆฟ์ด ์ ์šฉ๋œ ํŽ˜์ด์ง€๋“ค์„ ๋ Œ๋”๋ง ํ•ด์ค€๋‹ค.
  • json : json ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์•„์„œ ๋ณด๋‚ธ๋‹ค.