본문 바로가기
포스코x코딩온

[포스코x코딩온] 풀스택 부트캠프 15주차 정리 -1 3차 프로젝트 회고-1

by 김선지 2024. 1. 30.

01/27  ~ 01/28

웹 소켓 채팅 관련해서 다른 팀원분이 만들고 계신 것을 데이터베이스와 연동하기로 했다. 팀원분이 잘 만들어두셔서 웹 소켓은 잘 작동했지만 소켓의 경우 async를 활용하지 않기 때문에 바로 await로 sequelize 함수를 사용할 수 없었다.

그래서 위에 따로 함수를 만들어 sequalize 함수를 이용했고 이를 통해 연동할 수 있었다. 이건 나중에 mvc를 통해서 컨트롤러에 넣어야겠다.

socket과 db연동

근데 넣다 보니까 데이터베이스를 갈아엎을 필요가 있었다. 그 이유는 1:1 chat과 mono chat을 구분하기 위함에 있었는데

하나의 테이블에 두 개를 넣다 보니까 구분할 수 있는 방법이 없었다. 그래서 useridTo를 만들어서 1:1 chat이면 useridTo에는 상대방 userid를, monoChat일 경우에는 monoChat을 넣는 방법으로 해결할 수 있었다.

 

다만 이렇게 했을 때 monoChat이라는 user가 useridTo에 들어가야 하기 때문에 오류가 발생했다. (useridTo는 User 테이블과 1:N 관계) 유저 아이디에 새롭게 monoChat이라는 dummy 유저를 만듦으로써 해결할 수 있었다.

(아마도 다른 채팅 앱 사이트들은 유저가 회원탈퇴를 하면 데이터가 사라지지 않고 알수없음으로 뜨기 때문에 MULTY KEY 설정을 하지 않은 것 같다. 근데 나는 삭제하는 게 여기서는 낫다고 생각해서 깔끔하게 삭제했다. 갑자기 든 생각인데, MULTY KEY 상태로 회원탈퇴를 하면 user 테이블의 name을 알 수 없음으로 설정하는 방법도 있을 것 같다.)

 

// 추후에 알게 되었는데 일반적으로 채팅 로그의 경우는 비관계형 데이터베이스, NOSQL을 쓰는 것이 일반적이라고 한다.

하지만 이번 프로젝트의 경우에는 채팅에 있어서 유저 정보도 가져와야 하고, 채팅 하나하나에 얽혀있는 읽지않은 인원, 그리고 Chat Room에 얽혀있는 현재 접속중인 인원 등 채팅 로그에 대해서 관계가 활약할 일이 많기 때문에 RDBMS가 더 적절하지 않나. 하는 생각이 들었다.

 

같은 front public 폴더의 경로의 이미지를 가져오는데 하나는 가져오고 다른 하나는 못가져오는 일이 발생했다. 

그래서 개발자 페이지의 네트워크를 보았는데 서버를 한번 들리는 것을 확인할 수 있었다. 그래서 서버 public 폴더와 front public 폴더가 이름이 같아서 발생한 문제라고 예상했기에 서버 폴더 이름을 static으로 바꿔보았다. 하지만 작동하지 않았다. 한참을 찾다가 이미지 파일 이름과 이미지 패스 경로가 woman과 women으로 다른 것을 확인할 수 있었다...

그래도 퍼블릭에서 못찾으면 서버까지 가서 탐색한다는 사실을 알았기 때문에 괜찮은 소득이 아닐까 싶다.

 

남이 내 페이지에 들어갔을 때 볼 수 있는 searchUser 페이지를 만들었다. 그냥 마이페이지 깡통에다가 수정 버튼만 전부 없애고 수정 기능을 없앴다. 거기다가 팔로우 버튼과 채팅 버튼을 만들어놓으라고 해서 진짜 깡통만 넣어놨다.

 

01/29 

팔로우 기능을 좋아요 기능 했던 것처럼 토글 기능으로 만들어서 구현했다. 뭐 간단했다.

이거 버튼 바꾸는건 형이 해주겠지. 뭐 isFollowing 백에서 보내주니까 이걸로 state 만들어서 해주면 되지 않을까.

새로운 주문이 들어왔다. 

웹 소켓을 담당하던 분이 채팅을 만든 구조는 룸 이름을 만들고 버튼을 누르면 랜덤 id를 생성해서 새로운 방을 만들고 그 방 링크를 사용자에게 직접 url로 전달해서 들어오게 하는 구조였다.

근데 1:1 채팅은 그렇게 구현하는 것보다는 searchUser페이지에 있는 chat 버튼을 눌러야 룸이 만들어지고 그 방에 들어가져야 한다는 의견이 있었다. 좀 빡셀 것 같긴 한데 해볼 만 한것 같아서 해봤다.

 결론만 말하자면 다른 사람 마이페이지에서 대화하기를 눌렀을 때 만들어지지 않은 대화방이라면 웹소켓을 통해서 방을 만들고 그 만들어진 roomNum을 따로 axios를 보내서 가져왔다.

 하지만 다음날이 되어서 그냥 웹 소켓으로도 해결할 수 있을 것 같아서 해봤고 성공했다.

웹 소켓으로 create room을 보내면 거기서 room table을 생성한다. 하지만 room table을생성하는 함수 안에서 랜덤 roomNum을 생성했으므로 async function으로는 return 값을 받을 수가 없었다. 물론 그냥 랜덤 roomNum 생성을 밖으로 뺸 다음에 함수의 argument로 넣으면 될 것 같지만 이건 나중에 든 생각이었다.

그래서 생각이 든 해결책이 참조값을 활용하는 거였다. 참조값을 만들고 그 참조값을 인자에 넣은다음에 async function 안에서 할당해주면 그 값을 밖에서 쓸 수 있었고 이를 통해서 roomNum을 웹소켓으로 보내주고 프론트 단의 navigate를 통해서 이동할 수 있었다.
추가로 room create로 웹소켓을 보냈을 때 이미 만들어진 방이라면 그냥 findOne을 통해서 해당 값이 있다면 참조값 Arr를 통해서 해당 값을 받고 return해줬다. 이런 식으로 1:1 채팅 구현에 성공했다.

message 누르면 findOne을 통해서 있으면 거기 링크로, 없으면 새로 만들고 링크로 보내버린다

 

 

또한 포스트를 가져올 때 시간 역순으로 주되 팔로우 한 사람이 가장 위로 가야한다는 의견 또한 있었다. 다만 front 에서는 데이터를 그대로 map을 돌려야 하기 때문에 하나의 배열로 만들어서 쏴주는 작업은 백에서 해주는 게 좋을 것 같았다. (실은 마이페이지에서 그거 조작에 실패해서 내가 직접 front 단에서 새롭게 배열을 sorting했다.)

 

// SQL문법으로 데이터베이스에서 가지고 온 데이터에 접근하려면 data.dataValues << 이렇게 접근해야 하는데 이렇게 접근하지 않아서 실패했었다.

 

저번의 실패를 교훈삼아 이번에는 할 수 있을거라 생각했다. 일단 가장 중요한 건 boolean 값을 sorting 할 수 있나였는데 true는 1, false는 0이기 때문에 true - false는 1이기 때문에 숫자처럼 소팅이 가능하다는 포스트를 보았다.

그럼 해결할 수 있겠지. 라고 쉽게 생각했다.

처음에는 sort 함수에다가 return 값을 두개를 주었다. (return a.boolean - b.boolean || a.num -b.num) 이런식으로.

근데 제대로 소팅하지 못했다.

이유는 이게 첫번째 조건 두번째 조건이었기 때문이었다. 이건 첫번째 조건에서 소팅하지 못하면 두번째 소팅 방식으로 소팅한다는 의미였다. 다행히도 이 문제를 해결할 방법은 예전에 백준에서 풀었다.

해당 이미지처럼 두번 소팅을 하는거다. 다만 더 강한 조건이 마지막에 와야한다. (왜냐? 마지막에 소팅해야 다른 조건에 의한 소팅의 제약이 없기 때문.)

해당 식으로 하면 일단 시간 역순으로 정렬을 하고 나서 정렬된 것을 바탕으로 트루값이 앞으로 오게 정렬할 수 있다.

(이거는 내림차순이 아니고 오름차순이다... 왜냐면 포스트 페이지 프론트 담당하시는 분이 알아서 배열 reverse를 하셨기 때문이다. 이게 시간복잡도의 창조 손해인가.)

 

이걸 마치고 온 다음 주문은 1:1 채팅방 이름에는 상대방 이름이 나와야 한다는 것이었다. 뭐 방 이름을 상대방 이름으로 등록하면 해결될 거라고 생각했는데 그러면 그 상대방 아이디로 접속했을 때는 방을 만든 사람의 이름이 떠야했다.

 

음... 이건 진짜 빡셌다. 채팅방 room table에는 userid는 있는데 name 테이블은 없다. 그래서 sequelize의 include 속성을 이용해서 userid column에 해당하는 User 테이블의 name과 useridTo column에 해당하는 User 테이블의 name을 같이 가져오려고 했는데 실패했다. 같은 테이블에 외래키를 설정해놔서 제일 왼쪽 것 밖에 안가져온다.

그냥 sql로는 구현할 수 있을 것 같기 때문에 sequelize에서도 구현할 수 있을 것 같은데 내가 능력이 부족해서 실패한 것 같다. 

구글링 능력을 기르고싶다. 

뭐, 이가 없으면 잇몸으로 라고 했다.

그래서 findOne을 통해서 두개 다 가져왔다.

아래서 볼 수 있듯이 일단 userid 값이 들어있는 1:1 채팅 값을 모두 가져온다. 그 이후 result에 있는 userid와 useridTo에 있는 name 정보를 전부 가져와서 session에 있는 id 정보를 이용해서 name 값을 가져오고 이를 filter를 돌려서 반환해준다.

흠... 뭔가 더 간편한 코드가 있을 것 같긴 하다. 

 

이걸... 29일 하루만에 했다고?

거의 어제만 순코딩 9시간은 한 것 같다.