Node.js

Node.js + MongoDB 채팅기능 만들기3 소켓x[change stream(MongoDB)](SSE)

svdjcuwg4638 2023. 5. 24. 20:09

이전글

https://daehyuntsory.tistory.com/94

 

Node.js + MongoDB 채팅기능 만들기2 소켓x[EventSource](SSE)

메세지 발행을 해봅시다. 메세지 발행은 그냥 게시물 발행이랑 똑같습니다. 근데 댓글개념이기 때문에 부모 게시물도 기록해주면 끝이라고 했습니다. - /chat 페이지에서 원하는 채팅방을 하나

daehyuntsory.tistory.com

 

채팅방 누르면 서버에서 데이터를 보내주고 있습니다.

그 데이터를 실제 채팅메세지처럼 html로 보여주라고 했습니다.

그럼 자바스크립트로 "데이터 수신시 html 저기다가 만들어주세요" 라고 코드짜면 끝입니다

 

(chat.ejs)

      var selId;
      var eventSource ;

      // 채팅방 누를시 이벤트 발동
      $('.list-group-item').click((event)=>{
        
        $(event.currentTarget).css('background-color', '#eee');
        selId = $(event.currentTarget).attr('data-id');
        // 속성중 data-id의 값을 가져와 저장 (선택된 채팅방의 아이디)

        $('.chat-content').html('')

        if(eventSource != undefined){
          eventSource.close();
        }


        // write를 받기위한 클래스
        eventSource =  new EventSource('/message/'+ selId)

        // test란 이름으로 이밴트생성
        eventSource.addEventListener('test',(e)=>{
          var 가져온거 = JSON.parse(e.data)
          가져온거.forEach((i)=>{
            $('.chat-content').append(`<li><span class="chat-box">${i.content}</span></li>`)
          });
        })
      })

몇 줄을 추가했는데

1. 가져온 데이터를 다시 따옴표를 제거해서 { }, [ ] 로 만들어줍니다. 문자보다 array, object 자료 조작이 쉽습니다. 

2. 아마 가져온건 [{ }, { } ... ] 이렇게 생겼습니다. { } 안에 하나하나 메세지 document 들이 들어있을텐데

3. 그걸 반복문 돌리면 { } 하나씩 나옵니다.

4. 그거 안에 있던 메세지들을 <li></li> 태그로 만들어서 원하는 곳에 집어넣었습니다.

jQuery를 쓰는 경우 $(원하는요소).append(html태그) 이렇게 쓰면 html 추가가 가능합니다. 

 

중요

currentTarget를 사용한 이유는  target사용을하면 .list-group-item을 선택시 이벤트 발동하게 해놨는데 그 안에 태그가 여러가지가 있을것이다 내부요소의 태그를 누를시 값이 잘 안들오는 오류가 많다 하지만 currentTarget를 사용하면 값이 잘 들어오는걸 확인할 수 있다.

 

 

지금은 DB에 메세지가 하나 추가되어도 아무런 반응이 없습니다.

세상에 이런 채팅서비스는 없습니다. 

DB에 메세지가 추가되면 그걸 서버가 응답.write()로 바로 전송해줘야 실제 메세지 서비스같겠군요.  

"DB에 데이터가 하나 추가되면 바로 응답.write() 해주세요~" 라고 코드를 짜고 싶으면 

MongoDB 의 change stream 기능을 쓸 수 있습니다.

 

MongoDB change stream 기능

원래 데이터베이스는 수동적입니다.

서버가 명령하면 데이터 입출력만 얌전히 해줄 뿐인데 

change stream 기능을 이용하면 지가 동적으로 DB 변동사항을 감시해줍니다.

그리고 변동이 생기면 서버에게 업데이트 사항을 알려줍니다.

그럼 이제 자기주도적으로 일하는 DB가 되는데 

실시간 서비스 만들 때 이런거 쓰면 편리합니다.

 

change stream 쓰는 법 

(server.js)

const 찾을문서 = [
    { $match: { fullDocument.name : 123 } }
];
  
const changeStream = db.collection('message').watch(찾을문서);

changeStream.on('change', (result) => {
    console.log(result.fullDocument);
});

change stream 기능을 사용할 때 기본 코드 이렇게 써놓고 시작하면 됩니다. 

1. 우선 컬렉션에서 원하는 document만 감시하고 싶으면 $match 이런걸 이용해서 조건식을 적어주면 됩니다.

(위 코드는 DB에서 {name : 123} 인 document만 변동사항을 감시해줍니다.)

 

2. 그리고 watch(찾을문서)를 붙여줍니다. 

 

3. 그리고 on('change') 어쩌구 이벤트 리스너를 붙여주면

DB에서 변동사항이 생길 때마다 콜백함수 내부 코드를 실행해줍니다. 

 

3. 변동사항은 result.fullDocument 안에 저장되어있습니다. 

change stream에서 뭐 할 때는 어쩌구.fullDocument라고 자주 사용합니다.

왜 result.fullDocument 써야하는지 궁금하면 언제나 console.log로 출력해보면 됩니다.

 

 

▲ 예를 들어 컬렉션에 document가 하나 생겼을 때 result를 출력해보면

이런 데이터가 나옵니다.

새로운 document가 'insert' 되었다, 그리고 저장된 데이터는 fullDocument에 있다 

이렇게 바로바로 변동사항을 알려줍니다.

 

 

그래서 '/message/어쩌구'로 접속시 DB 변경사항을 실시간으로 감시하려면

 

저번시간에 했던 app.get('/message/:parentid' 부분 하단에 오늘 배운 코드를 추가하면 되겠군요. 

 

(server.js)

app.get('/message/:parentid', 로그인했니, function(요청, 응답){

  응답.writeHead(200, {
    "Connection": "keep-alive",
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache",
  });

  db.collection('message').find({ parent: 요청.params.parentid }).toArray()
  .then((결과)=>{
    console.log(결과);
    응답.write('event: test\n');
    응답.write(`data: ${JSON.stringify(결과)}\n\n`);
  });


  const 찾을문서 = [
    { $match: { 'fullDocument.parent': 요청.params.parentid } }
  ];

  const changeStream = db.collection('message').watch(찾을문서);
  changeStream.on('change', result => {
    console.log(result.fullDocument);
    var 추가된문서 = [result.fullDocument];
    응답.write(`data: ${JSON.stringify(추가된문서)}\n\n`);
  });

});

1. 누군가 app.get('/message/:parentid' 이런 실시간 소통채널에 입장하면 DB에서 게시물 쫙 가져오고 그러는데

2. change stream을 이용해서 DB 감시도 동시에 해줍니다. 

- 우선 { parent : 요청.params.parentid } 인 게시물들만 감시합니다.

- 그런 게시물들에 변동사항이 생기면 [result.fullDocument] 이걸 유저에게 보내줍니다. 

- 물론 [], {} 이런 자료들은 JSON으로 바꿔서 보내야합니다. 

 

그럼 뭐 이제 DB에 누군가 메세지를 추가로 전송해도 바로바로 유저에게 보내주겠군요.

그럼 이제 html로 그 추가 메세지들을 보여주기만 하면 되는 것입니다. 

오 이런 보여주는 코드는 저번 시간에 다 짜놨군요 

채팅기능완성

 

깃허브자료

https://github.com/svdjcuwg4638/learnNode.git

 

GitHub - svdjcuwg4638/learnNode

Contribute to svdjcuwg4638/learnNode development by creating an account on GitHub.

github.com