mongoDB & jQuery

이지우·2024년 6월 20일
0

멋사

목록 보기
9/16

날짜 추가

enter.html

<div class="mb-3">
  <label class="form-label">작성일</label>
  <input type="date" class="form-control" name="someDate">
</div><p></p>

server.js

mydb.collection('post').insertOne({
  title:req.body.title,
  content:req.body.content,
  date:req.body.someDate, // date 추가
})


enter.ejs로 변경

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

list 페이지 수정

<thead>
  <tr>         
    <th>제목</th>
    <th>작성일</th>
    <th>삭제</th>
  </tr>
</thead>
<tbody>
  <% for(let i=0; i < data.length; i++){ %>
  <tr>         
    <td><%= data[i].title %></td>
    <td><%= data[i].date %></td>
    <td><button class = 'delete btn btn-outline-danger' >삭제</button></td>
  </tr>
  <% } %>
</tbody>    


jQuery

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

<script>
	$(document).ready(function(){
        alert();
	});
</script>

ready()를 이용하여 문서가 모두 뜨면 콜백함수 실행

<head>
<script>
	$(document).ready(function(){
		btn.addEventListener('click', function(){
			alert();
		});
	});
</script>
</head>

<body>
	hi
	<button id="btn">전송</button>
</body>

이를 jQuery 사용하도록 변경

<script>
	$(document).ready(function(){
		// btn.addEventListener('click', function(){
		//    alert();
		// }); 
		$('button').click(function(){
			alert();
		});
	});
</script>

버튼이 하나만 있을 경우에는 문제 없음

버튼이 여러개가 있을 경우에 id나 class 사용

<head>
<script>
	$(document).ready(function(){
		// btn.addEventListener('click', function(){
		//    alert();
		// }); 
		$('.a').click(function(){
			alert();
		});
	});
</script>
</head>

<body>
    hi
    <button id="btn" class="a">전송</button>
    <button id="btn" class="a">전송</button>
    <button id="btn" class="b">전송</button>
</body>

삭제 기능 추가

server.js

app.post('/delete', (req, res) => {
    console.log(req.body, '삭제 완료');
});

list.ejs

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script>
        $('.delete').click(function(){
            $.ajax({
                type:'post',
                url:'/delete',
                data:{_id:'66731326c95262081745adf7'}
            })
            .done(function(result){
                console.log(result);
            })
            .fail(function(xhr, textstatus, err){
                console.log(err);
            })
        });
    </script>

콘솔에 삭제 id 값이 잘 넘어갔는지 확인
DB에는 아직 적용 안됨

원하는 id 가져오기

데이터셋 속성으로

<tr>         
	<td><%= data[i].title %></td>
	<td><%= data[i].date %></td>
	<td><button data-id = "<%=data[i]._id%>" class = 'delete btn btn-outline-danger' >삭제</button></td>
</tr>

...
<script>
$('.delete').click(function(e){
	let sid = e.target.dataset.id;
	$.ajax({
		type:'post',
		url:'/delete',
		data:{_id:sid}
	})
  ...
</script>

mongoDB delete 추가

server.js

app.post('/delete', (req, res) => {
    // console.log(req.body, '삭제 완료');
    mydb.collection('post')
        .deleteOne(req.body)
        .then(result => {
            console.log('삭제 완료');
            res.status(200).send();
        })
        .catch(err => {
            console.log(err);
        });
});

아까 받아온 id로 delete 해도 적용이 안됨
ObjectId 형식으로 바꾸어 적용해주어야 함

npm i objectid

const ObjId = require('mongodb').ObjectId;

...

app.post('/delete', (req, res) => {
    console.log(req.body._id);  // 문자열
    req.body._id = new ObjId(req.body._id);
    console.log(req.body._id);  // 객체

    mydb.collection('post')
        .deleteOne(req.body)
        .then(result => {
            console.log('삭제 완료');
            res.status(200).send();
        })
        .catch(err => {
            console.log(err);
        });
});

이제 db에서 확인해 보면 삭제되는 것이 확인됨

/list 페이지에서 확인하기 위해서는 새로고침 해야 함


같은 것을 가리키는 것의 변수명은 모두 같게 맞추기 권장


상태코드 이용

200 코드를 반환되면 list.ejs의 script에서 .done이 실행됨

.done(function(result){
	location.reload();  // 현재 주소 다시 요청
})

새로고침 방법

이제 삭제시 바로 목록에서 사라짐
/list 요청을 서버쪽에 다시 보내고 받아오는 방식임
요청 넘기는건 xhr로 비동기적으로 작업중인데 화면 갱신은 리로드 방식(동기)
-> 이것은 의도와 맞지 않음


비동기로 수정하기

삭제될 <tr> 부분을 찾아서 삭제되어야 함

DOM Tree

button이 눌린 이벤트가 발생한 td의 tr을 찾음(parent)

$('.delete').click(function(e){
	console.log(this);           
});

삭제버튼 클릭 시 발생하는 이벤트의 this를 출력해보면 button이 나옴

$('.delete').click(function(e){
	let _id = e.target.dataset._id;
	let item = $(this);
	$.ajax({
		type:'post',
		url:'/delete',
      	data:{_id}  // _id:_id를 함축적으로 표현
	})
	.done(function(result){
		// location.reload();  // 현재 주소 다시 요청
		item.parent('td').parent('tr').remove();
	})
	.fail(function(xhr, textstatus, err){
		console.log(err);
	})
});

삭제 실패 예외 처리

server.js

.catch(err => {
	console.log(err);
	res.status(500).send();
});

list.ejs

.fail(function(xhr, textstatus, err){
	console.log(xhr, textstatus, err);
})

server.js에서 collection 이름을 잘못 주는 방식으로 에러 발생시키기
-> 버튼 클릭 시 db는 삭제가 안되는데 tr은 삭제됨
-> catch가 수행되지 않음
-> throw err;로 작성해도 똑같음
-> 없는 collection 이름을 넣으면 새로 생성해버림!

collection 이름을 빼버리면 에러 발생함

log로 내용을 찍지 않고 alert(err) 실행 시


내용 페이지 생성

list.ejs 복사해서 content.ejs 생성 후 수정

<h1>상세내용</h1>
<h2>제목 : ...</h2>
<h3>내용 : ...</h3>
<h4>작성일 : 년월일</h4>


시멘틱 url 방식

글마다 글번호를 url 뒤에 붙여서 페이지를 각각 나눠주기

req 객체

  • header/body/params 형태
  • 네트워크 상에서는 아니고 객체로 만들어지면
app.get('/content/:_id', (req, res) => {
    console.log(req.params._id);
    res.render('content.ejs');
});

db 파라미터 검색

app.get('/content/:_id', (req, res) => {
    mydb.collection('post')
        .findOne({_id:new ObjId(req.params._id)})
        .then(result => {
            res.render('content.ejs');
        })
        .catch(err => {
            res.status(500).send();
        });
});

fineOne에서 deleteOne과 다르게 body가 아닌 객체로 넘기는 이유

  • get 방식에서는 body가 비어있음
  • id 값은 body가 아닌 params에 들어 있음

리스트에 링크

<a>는 무조건 get방식

list.ejs

<tbody>
    <% for(let i=0; i < data.length; i++){ %>
    <tr>         
        <td><a href = '/content/<%= data[i]._id %>'><%= data[i].title %></td>
        <td><%= data[i].date %></td>
        <td><button data-a = "b" data-_id = "<%=data[i]._id%>" class = 'delete btn btn-outline-danger' >삭제</button></td>
    </tr>
    <% } %>
</tbody> 

제목 부분에 <a> 추가


리스트에 db 나타내기

server.js

app.get('/content/:_id', (req, res) => {
    mydb.collection('post')
        .findOne({_id:new ObjId(req.params._id)})
        .then(result => {
            res.render('content.ejs', {data:result});
        })
        .catch(err => {
            res.status(500).send();
        });
});

render 시 data로 result(_id) 넘기기

content.ejs

<h1>상세내용</h1>
<h2>제목 : <%= data.title %></h2>
<h3>내용 : <%= data.content %></h3>
<h4>작성일 : <%= data.date %></h4>

content 페이지 수정

content.ejs

<div class = "container mt-4">
    <div class="card" style="width: 100%;">
        <div class="card-header">
            <h4 class="card-title"><%= data.title %></h4>
        </div>
        <div class="card-body">
            <p class="card-text"><%= data.content %></p>
            <p class="card-subtitle mb-2">작성일 : <%= data.date %></p>
            <a href="#" class="card-link">수정하기</a>
        </div>
    </div>
</div>

부트스트랩 적용 & 수정하기 추가


수정기능 추가

라우터 추가

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

수정하기 클릭 시 넘어가도록 content.ejs에 수정
<a href="/edit" class="card-link">수정하기</a>

작성되어 있던 데이터 전달

시멘틱 url 방식으로 전달

app.get('/edit/:_id', (req,res)=>{
    console.log(req.params._id);
    mydb.collection('post')
        .findOne({_id:new ObjId(req.params._id)})
        .then(result => {
            res.render('edit.ejs', {data:result});
        })
        .catch(err => {
            res.status(500).send();
        });
})

위에서 작성했던 content 부분과 render 파일명만 다름

edit.ejs 수정

<div class="mb-3">
    <label for="exampleFormControlInput1" class="form-label">제목</label>
    <input value="<%= data.title %>" name="title" type="text" class="form-control" id="exampleFormControlInput1">
</div>

<div class="mb-3">
    <label for="exampleFormControlTextarea1" class="form-label">내용</label>
    <textarea name="content" class="form-control" id="exampleFormControlTextarea1" rows="3">
        <%= data.content %>
    </textarea>
</div>

<div class="mb-3">
    <label class="form-label">작성일</label>
    <input value="<%= data.date %>" type="date" class="form-control" name="someDate">
</div><p></p>

input 태그에는 value 속성으로 값 넣어주고 textarea는 태그 사이에 작성

content.ejs

<a href="/edit/<%= data._id %>" class="card-link">수정하기</a>

수정 저장

edit.ejs

<form action="/edit" method="post">

post 방식으로 라우터 추가

server.js

app.post('/edit', (req, res) => {
    console.log(req.body);
})

몽고db에 update 반영
updateOne({조건}, {변경항목})

app.post('/edit', (req, res) => {
    console.log(req.body);
    mydb.collection('post')
        .updateOne(
            {_id:new ObjId(req.body._id)},
            {$set:{title:req.body.title, content:req.body.content, date:req.body.someDate } }
        )
        .then()
        .catch(err => {
            res.status(500).send();
        });
});

_id는 edit.ejs 안넘어옴
form 태그 안에 name:_id로 주어진 값이 없어서
-> 히든 타입으로 생성

<input type="hidden" name="_id" value="<%= data._id %>">

<input type="text" name="_id" value="<%= data._id %>" style="display:none">
이렇게도 가능

.then에 redirect로 /list 불러오게

app.post('/edit', (req, res) => {
    console.log(req.body);
    mydb.collection('post')
        .updateOne(
            {_id:new ObjId(req.body._id)},
            {$set:{title:req.body.title, content:req.body.content, date:req.body.someDate } }
        )
        .then(result => {
            console.log('수정완료');
            res.redirect('/list');
        })
        .catch(err => {
            res.status(500).send();
        });
});

redirect 대신 render를 해도 되는가?

render를 하려면 list.ejs에 넘길 data: result의 result에 수정된 data가 넘어가야해서 find()를 다시 해서 넘겨야 해서 복잡
-> 위에 작성했던 get방식으로 요청하여 redirect로 불러오기


성능 향상

get방식의 /edit

content에는 이미 데이터가 다 있는 상태
수정하기 버튼을 눌렀을 때 _id만 가지고 옴
db에 그 값을 가지고 가서 edit.ejs에 필요한 것을 불러와서 사용함

수정하기 화면에 작성되어 있던 데이터 그대로 띄우는 것이니 db에 갔다오지 않고 화면에 있던 데이터를 바로 req에 있는 data를 edit.ejs에 넘겨 렌더링 하게 하면 db에 가서 find()가 생략됨

profile
노력형 인간

0개의 댓글