본문 바로가기

node js

[Node.js] CRUD 구현하기 (Feat.ToDo 리스트)

1. 데이터 추가

db.collection("post").insertOne({ title: req.body.title, date: req.body.date }, function (error, result) {
  console.log("할일 저장완료");
});

데이터 추가는 insertOne({추가할데이터}, 콜백함수)을 이용한다.

주의할 점은 NoSQL은 모든 데이터를 Object 형태로 저장해야한다.

좋은점은 내가 아무렇게나 저장해도 문자면 string, 숫자면 int 이런식으로 알아서 저장이되기 때문에 schema를 신경쓸 필요가 없다. 근데 이게 단점이 될 수도 있다. (또 단점으로는 JOIN 연산을 수행하기 어렵다는 점이 있다.)

_id는 고유번호로 자동으로 부여된다. 내가 직접 부여할수도 있다.

2. DB 데이터를 브라우저에 촤라락 보여주기

먼저 ejs를 설치한다. npm i ejs.

ejs는 html을 더 쉽게 쓸 수 있게 해주는 템플릿 엔진이다.

라이브러리를 설치하면

app.set("view engine", "ejs");

이렇게 세팅을 해준다.

app.get("/list", function (req, res) {
  res.render("list.ejs");
});

ejs파일을 뿌려주는 방법은 res.render을 이용하면 된다.

이 때 주의할 점은 ejs파일은 항상 views라는 폴더안에 있어야한다. 안그러면 에러난다..

app.get("/list", function (req, res) {
  db.collection("post")
    .find()
    .toArray(function (error, result) {
      console.log(result);
      res.render("list.ejs", { posts: result });
    });
});

db.collection('post').find().toArray(콜백함수)이런식으로 collection안의 모든 데이터를 가져올 수 있다. 데이터를 가져오면 콜백함수에서 res.render로 ejs에 Object데이터를 넘겨준다.

<% for (var i = 0; i < posts.length; i++) { %>
<h4>할일제목: <%= posts[i].title %></h4>
<p>할일 마감날짜 : <%=posts[i].date %></p>
<%} %>

ejs에서는 이런식으로 뿌려줄 수 있다. posts는 res.render로 넘겨준 데이터다.

ejs 문법에는 <%= %>와 <% %>가 있다. 등호(=)가 있는거는 안에 출력할 변수를 넣겠다는 것이고, 등호가 없는 것은 javascript 문법을 쓰겠다는 뜻이다.

3. 게시글에 글번호 부여하기(auto increment)

글을 저장할 때 꼭 해야할게 글번호 부여한는 것이다. 어떤 글이 삭제되더라도 id는 영구하게 남아있는게 좋다. 나중에 수정 시점에 따라 문제가 생길 수 있기 때문이다.

그런데 NoSQL에는 auto increment가 없다. 그래서 하나의 컬렉션, 예를 들어 counter라는 컬렉션을 생성한다고 하자. 그 counter라는 컬렉션에

name: "게시물개수"
totalPost: 0

이런식으로 데이터를 생성하고, totalPost를 계속 1증가시키면서 수정하면 auto increment를 구현할 수 있다.

app.post("/add", function (req, res) {
  db.collection("counter").findOne({ name: "게시물개수" }, function (error, result) {
    console.log(result.totalPost);
    let totalPost = result.totalPost;

    db.collection("post").insertOne(
      { _id: totalPost + 1, title: req.body.title, date: req.body.date },
      function (error, result) {
        console.log("저장완료");
        db.collection("counter").update({ name: "게시물개수" }, { $inc: { totalPost: 1 } });
      }
    );
  });
});

게시글을 추가할 때는 위에 코드처럼 먼저 게시물개수를 가져온 후, 그 수를 저장해둔다. 여기서는 totalPost라는 변수에 저장했다. 그 다음에 데이터 추가 코드를 짠다. totalPost+1을 해서 저장하고, counter 컬렉션에 있는 게시물개수도 1 증가시킨다.

counter 컬렉션에 있는 게시물개수를 1증가시킬 때는 update를 쓰는데, 데이터를 수정할 때 operator(연산자)를 써야한다.

기본적인 연산자는

  • $set(변경)
  • $inc(증가)
  • $min(기존값보다 적을때만 변경)
  • $rename(key값 이름변경) 이정도가 있다.

개시물개수를 1증가 시킬 때는 증가 연산자 $inc를 사용하면된다. $inc: {totalPost: 얼마마큼증가할건지} 이런식으로 입력한다.

4. 게시물 삭제하기 (Feat. ajax)

특정 게시물을 삭제를 하는 방법을 생각해보면 간단하다.

  1. 먼저 서버에 삭제 요청을 함.
  2. 서버에서 삭제를 함. 끝!

인데... HTML상에서는 DELETE요청을 할 수 있는 방법이 없다.

그래서 해결방법이 두 가지가 있는데,

  1. method-override 라이브러리 사용 => form 에서 delete요청 가능해짐
  2. ajax 요청

ajax는 매우 자주 쓰이니 여기서 알아보도록 하자.

ajax는 새로고침없이 서버랑 통신할 수 있게 도와주는 JS문법이다. 여기서 통신이란 서버한테 GET/POST/PUT/DELETE 요청을 하는 것을 말한다.

$.ajax({
  method: "DELETE",
  url: "/delete",
  data: { _id: postId },
})
  .done(function (result) {
    // 요청 성공시 실행(2xx 코드가 왔을 때)
    console.log(result);
  })
  .fail(function (xhr, textStatus, errorThrown) {
    // 요청 실패시 실행(4xx 코드가 왔을 때)
    console.log("실패", xhr, textStatus, errorThrown);
  });

위에 코드는 ajax요청을 하는 코드이다. 해석하면 "/delete 경로로 DELETE 요청을 보내는데 '게시물번호'라는 데이터를 실어서 보냅니다~"라는 뜻이다. 요청이 끝나고 받은 결과를 콘솔로그로 출력해주세요~~라는 뜻.

app.delete("/delete", function (req, res) {
  req.body._id = parseInt(req.body._id); // 데이터를 주고받을 때 문자로 치환되는 경우가 있기 때문에 int로 변환
  db.collection("post").deleteOne(req.body, function (error, result) {
    res.status(200).send({ message: "성공했습니다." }); // 요청 성공
  });
});

ajax로 서버에 삭제해달라고 요청을 하면 서버에서는 그냥 삭제해주면 된다. deleteOne 응답코드를 보내서 ajax요청 후, done부분에 코드가 실행될 수 있도록 한다. 실패하면 fail부분의 코드가 실행된다.

응답코드

  • 200 요청성공
  • 400 요청실패
  • 500 서버문제로 요청실패 서버는 브라우저한테 응답코드로 대답한다.

5. 게시글 조회하기 (상세페이지)

app.get("/detail/:id", function (req, res) {
  db.collection("post").findOne({ _id: parseInt(req.params.id) }, function (error, result) {
    res.render("detail.ejs", { data: result });
  });
});

/detail/:id이렇게 콜론(:)뒤에 오는 변수를 파라미터로 받게된다. 그 파라미터는 req.params.id로 접근할 수 있다.

6. 데이터 수정

form태그에서 PUT/DELETE를 쓰는 방법 (Feat. method-override)

form태그의 method속성에는 GET/POST만 올 수 있고, PUT/DELETE는 지원 안된다. form태그에서도 PUT/DELETE를 쓰려면 method-override를 사용하는 방법이 있다.

npm i method-override
const methodOverride = require("method-override");
app.use(methodOverride("_method"));

이렇게 세팅해주면 html form태그에서 사용할 수 있다.

데이터 수정

<form action="/edit?_method=PUT" method="POST">
  <input type="hidden" name="id" value="<%= data._id%>" />
  <input type="text" name="title" value="<%= data.title%>" />
  <button type="submit">Submit</button>
</form>

action 속성을 /edit?_method=PUT이런식으로 채워주면, /add에 PUT요청을 한다는 뜻이다. 이 때 method는 POST로 적어줘야 한다.

수정할 때는 id데이터를 hidden으로 넘겨준다.

app.put("/edit", function (req, res) {
  db.collection("post").updateOne(
    { _id: parseInt(req.body.id) },
    { $set: { title: req.body.title, date: req.body.date } },
    function (error, result) {
      res.redirect("/list"); // 페이지 이동
    }
  );
});

수정후 페이지 이동은 res.redirect를 이용한다.