본문 바로가기

JavaScript

jQuery 안 쓰겠다고 고집을 고집을 아주

부리다가 머리 깨져서 닷새 만에 글을 쓰게 됐습니다. ajax 요청 보내는 부분에서 바닐라js로 하려다가 아주 혼쭐이 났습니다. 뒤에서 자세하게 얘기하도록 하고 오늘은 근황 없이 바로 시작해봅시다.

 

그보다도 오늘 허윤회 생일입니다. 저 공부하는데 있어서 정말 많은 도움을 주는 친구인데 마침 이렇게 축하할 수 있어서 기분이 좋네요 항상 고맙다 윤회야 생일 축하혀~

 

파트 2에 들어가면서 MongoDB를 쓰기 시작했습니다. MongoDB를 직접 설치하진 않았구요, MongoDB Atlas라는 클라우드 서비스를 이용하게 되었습니다. 계정을 만들고, DB를 만들고, 거기에 콜렉션을 생성하는 일련의 과정을 거치면서 조금 멈칫하는 지점이 있었는데요, 클라우드 시스템이나 서비스에 대한 이해가 부족한 채로 이 기술을 받아들여도 되는가에 대한 망설임 같은 게 있었달까요. 

 

아무래도 이게 비전공자로서 계속 드는 생각인데 CS의 기초부터 시작해서 네트워크 등 기반이 되는 지식이 없는 상태로 여러 기술들을 배우고 사용하는 게 여간 마음이 불편한 일이 아닐 수 없습니다. 물론 저것도 공부하면 될 일이긴 하지만 순서가 잘못되지 않았나 하는 생각이지요. 여튼 그래도 뭐 어쩌겠습니까 일단 배우고 써야겠죠?

 

우선 MongoDB에서 데이터베이스가 하나의 폴더라고 한다면 콜렉션은 그 안에 들어있는 엑셀 파일이라고 생각하면 좋을 것 같습니다. 물론 MongoDB는 비관계형 데이터 베이스이기 때문에 엑셀에 비유하는 건 조금 이상하긴 하지만 뭐 그렇습니다. 여기서 또 비관계형 데이터 베이스가 뭐냐, 비관계형이 있으면 관계형도 있는거냐, 그게 뭐냐 씹덕아 하실 것 같은데 제 입으로 설명하면 입이 아프구요, 저는 사실 강의에서 나온 부분을 따로 가져다가 비공개 포스트로 돌려놓은 게 있으니 저만 보고 저만 만족하고 저만 이해하고 넘어가도록 하겠습니다^^

 

그래서 일단 제 MongoDB 계정에 todoapp이라는 데이터베이스를 만들었구요, 그 안에 post라는 콜렉션을 만들었습니다. 그리곤 제 작업폴더로 돌아가서 터미널 창에 npm init MongoDB 인가 install인가로 MongoDB를 쓸 준비를 해뒀구요, 근데 이거 할 때 강의에서 명시한 버전 안 쓰고 최신 버전으로 내려받았다가 오류 나서 3.6.1버전인가? 다시 내려 받음ㅎㅎ,,,(고집 1스택) 근데 또 최신 버전 안 쓰는 게 마음에 걸려서 강사에게 이거 최신 버전 안 써도 됨? 현업에선 보통 어케 함? 물어봤는데 버전은 회사마다 다르고 최신 버전 나올 때마다 갈아 끼우는 건 대공사라서 이전 버전을 이어 쓰는 경우가 많다고 하는 말을 듣고 나서야 한시름 마음 편히 강의를 이어나갔습니다.

 

자 그럼 데이터베이스 만들어 놨고, 콜렉션도 만들어 놨고, 작업 폴더에도 MongoDB 받아놨고 이제 할 일은 정말 가져다 쓰는 일 밖에 남지 않았습니다. 우선 처음에 express 라이브러리를 불러오는 것처럼

 

 

이런 코드를 적고 시작합니다. 그리고는 저렇게 생성된 MongoClient 객체와 제 데이터베이스를 연결해주면 되는데, 

 

 

이렇게 생긴 코드로 연결해줍니다. 저기 빨갛게 칠한 부분은 제 데이터베이스 비밀번호입니다^^ 누가 와서 뭐 하진 않겠지만 일단 가려봄. db라는 변수를 일단 선언해두고, MongoClient와 제 데이터 베이스를 연결해줍니다. 연결이 된 후엔 .connect()의 두 번 째 인자로 들어간 콜백 함수가 실행되는데 이전에 8080포트로 서버를 여는 코드까지 저기에 넣어버립니다.

 

내 서버 파일에 몽고디비 연결 - 미리 선언한 함수에 데이터베이스 할당 - 그리고 서버 짜자잔 열기

 

의 순서로 진행이 되는 거지요. 이후에는 내용을 요약하자면 굉장히 간단합니다. POST 요청으로 받은 데이터를 콜렉션에 집어 넣는 것, 그리고 데이터를 넣을 때마다 id를 지정해주어야 하는데 그걸 원만하게 하는 방법, DELETE 요청을 받았을 때 데이터를 삭제하는 것 정도로 요약할 수 있겠네요. 그 사이에 .ejs 확장자를 배우기도 하고 콜렉션에 저장된 데이터의 내용을 변경하는 문법도 배우게 됩니다. 

 

우선 POST 요청에 담겨온 데이터를 콜렉션에 저장해보도록 할까요. 근데 그 전에 POST요청을 보내는 페이지 코드를 봅시다. https://localhost:8080/write로 들어가면 할 일의 제목과 세부사항을 적는 페이지가 뜨는데요, 거기 form 태그가 이렇게 생겼습니다.

 

 

form 태그의 속성으로는 어느 url로 보낼 지 action 속성이 적혀있구요, 어떤 방식으로 메세지를 전송할지도 딱 적혀 있습니다. 그리고 각 input 태그에는 name 속성이 적혀있는데요, 이제 저 input에 할 일 내용을 야무지게 적고 저장하기 버튼을 누르게 되면 데이터가 서버로 전송이 됩니다. 이 데이터를 받는 서버에선 그럼 어떻게 저 데이터를 받을까요

 

 

이런 식으로 받습니다. 진짜 개더럽죠? 일단 40번 줄에 있는 코드는 알아 먹을만 합니다. /add 라는 url로 POST 요청이 오면 .post()의 두 번 쨰 인자로 들어간 콜백함수가 실행됩니다. 아마 우리가 보낸 데이터는 저 콜백함수의 첫 번 째 인자인 req에 담겨 있겠군요,,, 다른 거 말고 43번 줄에 있는 코드를 먼저 봅시다. 앞서 db라는 변수에는 우리의 데이터베이스(todoapp이라는 이름)을 할당한 적이 있었구요, 그 데이터베이스에서 'post'라는 콜렉션을 찾아줍니다. 그리고는 insertOne() 함수를 이용해 말 그대로 새로운 데이터를 집어 넣어주는 겁니다. 데이터를 집어 넣을 때는 object 타입으로 넣는 모습이 보이구요. 

 

insertOne()의 인자로 전달된 object를 보아하니 저희가 앞서 전달한 데이터는 req.body에 담겨 있나봅니다. 그렇다면 저기 저 _id는 뭘까요? MongoDB는 콜렉션의 데이터에 각 데이터마다 고유한 임의의 id를 부여합니다, _id라는 이름으로 말이죠. 만약 우리가 { name : 'Kim', age : 19 }라는 데이터를 콜렉션에 추가하면 콜렉션에선 { _id : 132lku2134, name : 'Kim', age : 19 } 형식으로 데이터를 저장합니다. 그런데 각 데이터의 id가 임의로 부여돼서 차마 입으로 담기 어려울 만큼 어려운 것보다 우리가 id까지 딱 정해주고 데이터를 저장하는 게 이후에 데이터 관리에 더욱 용이하지 않을까요? 그래서 이제 42번 줄에 있는 코드가 생기게 됩니다.

 

42번 줄에 들어간 코드를 설명하기 앞서서 todoapp 데이터 베이스에 counter라는 콜렉션을 추가했다는 말씀을 미리 드려야겠군요.

 

totalPost는 처음에 0으로 시작했습니다.

 

우리는 post 콜렉션에 데이터를 추가할 때마다 부여할 id 값을 여기 counter 콜렉션에서 가져다 쓸 겁니다. 저 위에 코드를 다시 볼까요??

 

 

자 우선 '/add'라는 url로 POST 요청이 오면 데이터베이스에서 counter라는 콜렉션을 갖고 옵니다. 그리곤 .findOne()을 사용해서 어떤 데이터를 하나 찾아옵니다. .findOne()의 첫 번 째 인자로는 쿼리문이 들어가는 게 보입니다. 그리고 .findOne()의 두 번 째 인자로 콜백함수가 들어가는데 콜백함수의 인자에 result에는 우리가 방금 찾아온 데이터가 들어가게 됩니다. 그러면 이제 43번 줄에 있는 코드에서 _id : result.totalPost + 1이 이해가 되겠지요. +1이 들어간 이유는 totalPost가 0에서부터 시작해서 첫 데이터를 저장할 때 _id에 1을 부여하고 순차적으로 오르는 번호를 쓰기 위함입니다. 

 

그래서 post 콜렉션에 .insertOne() 함수로 데이터를 저장하고 난 뒤에 또 실행되는 콜백함수가 있는데요, 여기선 counter 콜렉션의 totalPost의 숫자를 바꿔줘야 합니다. 그래야 post에 저장되는 데이터마다 다른 _id 값을 가지니까요. 여기에 오기까지 콜렉션에서 데이터를 찾아오는 것, 콜렉션에 데이터를 추가하는 것이었는데요, 이번에는 데이터를 수정하는 법을 쓰게 됩니다.

 

45번 줄을 보면 바로 감이 오시죠 counter라는 콜렉션을 찾아서 .updateOne()이라는 함수를 사용한다-가 기본 골조인데 참 나 .updateOne() 함수에는 인자가 셋이나 들어갑니다. 첫 인자는 어떤 데이터를 바꿀지, 두 번 째는 어떻게 바꿀지, 그리고 세 번 째는 바꾸고 난 뒤에 실행할 콜백함수 입니다. 첫 번 째 인자로 어떤 데이터를 바꿀지 선택할 땐 위의 findOne()함수에서 썼던 것처럼 쿼리문으로 인자가 들어가구요, 물론 {name : 'postCount'}를 넣었다고 해서 저것만 갖고 오는 게 아니고 name : postCount인 데이터 전체를 갖고 오게 되는 겁니다. 그리고 두 번 째 인자엔 operator를 사용한 데이터가 들어가게 됩니다. 

 

{operator : {바뀔 내용}} 과 같은 형식으로 들어오는데요, 예를 들면 {$set : {totalPost : 23}}은 totalPost를 23으로 변경하는 게 되구요, {$inc : {totalPost : 23}} 는 기존 totalPost 값에 23을 더해주세요~가 됩니다. 

 

후 그럼 지금까지 한 걸 한 번 쭉 정리해봅시다

 

MongoDB 계정을 만들었구요, Atlas라는 클라우드 서비스를 이용해서 데이터베이스를 하나 생성했습니다. 그 안에 콜렉션을 몇 개 만들었구요. 서버와 데이터베이스를 연결했고 '/write' 페이지에서 전송하는 데이터를 받아서 데이터베이스 콜렉션에 저장까지 했습니다. 여기서 저장할 땐 다른 콜렉션의 데이터를 활용해 _id 값을 설정했구요(이걸 대충 auto increment 라고 합니다. DB에 항목을 추가할 때 마다 id 값이 자동으로 1 증가시켜서 저장하게 해주는 개념) 

 

자 그럼 우리가 저장한 데이터들을 보여주는 페이지도 필요하겠지요. 여기서 .ejs 확장자가 나오는데요. ejs 파일은 html 파일과 다를 게 하나 없습니다. 하나 다른 게 있다면 서버에서 데이터를 받아와서 그걸 페이지에 렌더링 해줄 수 있다는 점이겠지요. 우선 서버에서 '/list'라는 페이지로 GET 요청이 들어왔을 떄 어떻게 처리하는 지 코드를 보고 갑시다.

 

 

'/list'라는 url로 GET 요청이 들어오면 서버에선 우선 post라는 이름의 콜렉션을 가져와서 .find() 함수를 통해 콜렉션의 모든 걸 가져옵니다. 말 그대로 모든 것입니다. 콜렉션의 데이터 뿐만 아니라 메타 데이터까지 가져옵니다. 여기에 .toArray()라는 함수를 뒤에 붙이면 교통정리가 되는데요, .toArray()의 인자인 콜백함수에서 result라는 인자가 post 콜렉션의 데이터를 담은 array 자료가 됩니다. 

 

앞서 사용한 .findOne() 함수보다 굉장히 복잡하지요,,,?? 여튼 이렇게 갖고 온 데이터를 응답에 실어서 ejs 파일과 함께 보내는데 그 때는 .render() 함수를 사용합니다. 이전에 GET 요청이 들어와서 html 파일을 넘겨줄 땐 .sendFile() 함수를 사용한 것과는 또 다른 점이네요. .render()의 인자로는 렌더링할 ejs 파일과 ejs파일에서 사용할 데이터가 들어갑니다. 55번 줄의 경우 우리가 콜렉션에서 가져온 데이터 result를 posts라는 이름에 담아 보냈군요

 

 

그럼 ejs 파일에선 이런 식으로 사용합니다. ejs 파일은 정말 html 파일과 다를 게 거의 없는데요 html 태그를 쓰는 와중에 <%= XXX %>라는 기호를 사용할 수 있게 됩니다. 그리고 저 XXX가 적힌 부분엔 자바스크립트 코드가 들어가 동작할 수 있게 해준다는 게 ejs 파일의 핵심입니다. 앞서 서버에서 posts 라는 이름에 담아 넘긴 콜렉션의 데이터를 자유자재로 사용하는 모습.

 

자 그래 이제 진짜 다 한 것 같다 그쵸. 데이터베이스 만들어~ 거기에 데이터 넣어~ 그것도 id 지정해서 넣어~ 그 때마다 데이터 수정해~ 데이터 꺼내와서 또 보여줘~ 하지만 하나 남았죠? 바로 삭제입니다. 제가 약 나흘간 삽질한 부분이죠. 삽질한 이유는 제 고집입니다(고집 2스택).

 

강의에서는 해당 부분을 가르칠 때 제이쿼리를 사용했습니다. 하지만 저는 제이쿼리를 사용하지 않으려고 했구요. 실제로 전에 자바스크립트로 Web UI 만드는 강의에서도 제이쿼리를 가르쳤지만 꾸역꾸역 바닐라 js로 해온 사람입니다 제가. 그러는 이유? 그러고 싶으니까. 제이쿼리로 ajax 요청을 보내는데 아주 간편하게 보내더라구요. 자바스크립트로 ajax 요청 보내려면 fetch() 함수를 쓰고 뭐 난리를 쳐야하는데 말이죠,, 근데 이 fetch() 함수가 말을 안 들어서 진땀을 좀 뺐습니다. 삽질한 내용을 미주알 고주알 더 적고 싶지만 그러기엔 정말 길고 지루한 내용이고 사실 어찌 보면 제 게으름이 한 몫한 부분이기 때문에 딱 결과만 놓고 얘기하도록 하겠습니다.

 

우선 서버로 DELETE 요청을 해야합니다. 근데 ajax로 요청을 보내려고 합니다. 왜냐하면 html에서는 DELETE 요청을 보낼 수 없기 때문입니다. GET 요청과 POST 요청은 잘만 보내더니 어이가 없죠? 그래서 method-override라는 라이브러리를 사용하거나 ajax 요청으로 DELETE 요청을 해결해야 하는데 ajax를 쓰기로 합시다. 

 

자바스크립트에서 ajax 요청을 보내려면 fetch() 함수를 사용합니다. 그리고 우리는 그 동안 fetch() 함수에 어떤 url을 인자로 전달하고 곧바로 .then()을 붙여서 실행할 코드를 적곤 했습니다. 그 말인 즉 fetch() 함수에는 인자가 하나구나-인데 사실 그렇지 않았다는 사실. fetch() 함수는 사실 인자를 2개 받습니다. ajax 요청을 보낼 url과 보내는 요청에 대한 정보를 담은 object가 그것입니다. 두 번 째 인자에는 어떤 방식으로 요청을 보낼 지, 보내는 요청의 headers는 뭔지, body에는 뭘 담아 보낼 건지 가 담겨있는데 이 어떤 방식으로 보낼지-의 기본값이 GET 요청이라 사실 우리가 그 동안은 두 번 째 인자의 존재를 몰라도 됐던 것이죠. 말로만 하니 참 아리까리 하죠? 코드로 봅시다

 

 

delete라는 클래스를 가진 버튼 중 가장 첫 번 째 버튼을 누르면~ '/delete'라는 url로 POST 요청을 보낼 건데(DELETE 요청은 데이터를 넘기는데 가끔 오류가 있어서 일단 POST 요청으로 썼습니다. ㅈㅅㅋㅋ) 요청의 headers는 000이고~ 요청의 body에는 0000이라는 데이터를 넘겨서 보내줘~라는 내용의 코드입니다. dataset.id는 일전에 다룬 적 있으니 패쓰-

 

이제 서버에서 저렇게 넘어온 요청을 처리해야하는데요, 그 전에 json으로 넘어온 데이터를 express 라이브러리가 잘 이렇게 만지작 하려면 서버 파일 상단에 

 

 

이런 코드를 적어놔야 합니다. 그리고는

 

 

이런 식으로 처리하게 됩니다. 요청의 body에 담겨진 _id라는 데이터의 값은 문자열로 전달되기 때문에 정수로 변환을 하구요, post 콜렉션을 찾아서 deleteOne() 함수를 실행해주는데 이 함수 역시 인자로 쿼리문을 받는 모습, 그래서 전달받은 쿼리문을 변수 그대로 갖다 넣는 모습~ 이후에는 뭐 콘솔창에 삭제 잘 됐슈~ 하는 내용이니 넘어가도록 합시다. 

 

이후에는 url parameter를 배웠는데요. 사실 오늘 분량 보면 아시겠지만 정말 많이 쓴 것 같으니 대충 코드 복붙하고 넘어가는 걸로 합시다 우리,,, 저도 인쟈 씻고 잘랍니다,,

 

server.js
detailPage.ejs

 

내일부턴 다시 진도 나갈 수 있음에 감사하며 다시 한 번 열심히 해보겠습니다. 요 며칠 삽질한다고 게으름도 좀 많이 피웠거든요

ㅎㅎ,,, 그럼 20000