상세 컨텐츠

본문 제목

구글파이어베이스를 사용해 노드js 웹서비스 만들기_4/5

노드js·자바스크립트

by 김일국 2023. 12. 28. 12:57

본문

### 지난번 댓글 기능을 추가하기 위한 준비를 해 보았습니다. (아래)

현재 작업 중인 소스는 아래 깃 허브에 올려 놓았습니다.(단, 서비스계정키 파일은 보안때문에 제외 시켰습니다.)

 -. 표준노드js 웹서비스 코딩 소스 : https://github.com/miniplugin/nodejsboard 

 -. K-PaaS 플랫폼사용해 배포 : https://digitalsolveup.kr/platform.do 

 -. 표준노드js 앱 결과확인 URL : https://nodejsboard.apps.emergency-cloudplatform.kr/ 

오늘은, 댓글 창 디자인에 입력, 조회, 수정, 삭제 기능을 추가해 보았습니다.

게시글 CRUD 와 비슷하면서, 첨부파일+검색 기능이 빠져 더 간단했습니다.

그리고, 댓글 구현엔 SPA(Single Page App)처럼 1페이지에서 CRUD 및 페이징이 가능하게 되었습니다.

즉, 게시판 CRUD는 페이지 이동이 되면서 작동이 되지만, 댓글은 페이지 이동 없이 한 페이지에서 CRUD가 됩니다.

위 코딩 소스 중 게시판 서버코드는 board3.js 이고, 댓글 서버코드는 reply.js 입니다.(간단한 댓글 서버 코드 확인-아래)

var express = require('express');
var router = express.Router();
var dateFormat = require('dateformat');

const { firebase, db } = require('../firebase_config');

// 페이징 변수 초기화 start : 시작점 doc정보, next: 다음 목록에 대한 정보
var pagingObj = {
    prev: null,
    next: null,
    size: 2,
}
let mypromise = (prevDate, brdno) => {
    return new Promise((resolve, reject) => {
        let query = db.collection('reply').orderBy("brddate", "asc");
        if (brdno) {
            query = query.where('brdno', '==', brdno);
        }
        if (prevDate) {
            console.log("페이징 번호1 : ", Number(prevDate));
            //query = query.startAt(req.query.start); 실행이 적용되지 않아서 where 조건으로 변경
            query = query.where('brddate', '>', Number(prevDate));
        }
        query.limit(pagingObj.size)
            .get()
            .then((snapshot) => {
                console.log('여기', snapshot.docs[pagingObj.size - 1].data().brddate);
                resolve(snapshot.docs[pagingObj.size - 1].data().brddate);
            })
            .catch((err) => {
                console.log('Error getting documents', err);
                reject("실행에러")
            });
    });
}
router.get('/reply_list', async function (req, res, next) {
    var query = db.collection('reply').orderBy("brddate", "desc");
    if (req.query.brdno) {
        console.log(req.query.brdno);
        query = query.where('brdno', '==', req.query.brdno);
    }
    if (req.query.prev) {
        console.log("페이징 번호2 : ", Number(req.query.prev));
        //query = query.startAt(req.query.start); 실행이 적용되지 않아서 where 조건으로 변경
        query = query.where('brddate', '>', Number(req.query.prev));
        await mypromise(req.query.prev, req.query.brdno)
            .then((result) => {
                query = query.where('brddate', '<=', Number(result));
                console.log('여기2', result);
            })
            .catch((err) => {
                console.log(`Error getting documents ${err}`);
            });
    }
    if (req.query.next) {
        console.log("페이징 번호3 : ", Number(req.query.next));
        //query = query.startAt(req.query.start); 실행이 적용되지 않아서 where 조건으로 변경
        query = query.where('brddate', '<', Number(req.query.next));
    }
    query.limit(pagingObj.size)
        .get()
        .then(async (snapshot) => {
            pagingObj = {
                size: pagingObj.size,
                prev: snapshot.docs[0], // document들 안에서 가장 첫번째 것을 가져온다. (내림차순이라서 변수명이 반대이다.)
                next: snapshot.docs.length === pagingObj.size ? snapshot.docs[snapshot.docs.length - 1] : null
                // 가져오는 데이터 갯수를 4개로 지정했는데 3개 밖에 없을 수 있다, 
                // 이때 next가 지정한 데이터 갯수(4) 가 아니라면 null을 넣어준다. 다음(next)이 없다는 뜻.
            }
            console.log("페이징 번호4 : ", snapshot.docs.length, "===", pagingObj.size);
            if (snapshot.docs.length == 0) {
                res.json({ pagingObj: pagingObj, message: 'nopaging' });
            } else {
                let rows = []; // DB출력 리스트 변수
                snapshot.forEach(async (doc) => {
                    var childData = doc.data();
                    childData.brddate = dateFormat(childData.brddate, "yyyy-mm-dd hh:mm");
                    rows.push(childData); //ejs에 보낼 데이터 추가
                });
                //console.log('댓글리스트', rows);
                res.json({ rows: rows, pagingObj: pagingObj, message: 'ok' });
            }
        })
        .catch((err) => {
            console.log('Error getting documents', err);
            res.json({ message: 'fail' });
        });
});

router.post('/reply_write', function (req, res, next) {
    if (!req.session.logined) {
        res.redirect('/board/loginForm');
        return;
    }
    var postData = req.body;
    if (!postData.replyno) {  // new
        postData.brddate = Date.now();
        var doc = db.collection("reply").doc();
        postData.replyno = doc.id;
        postData.brdno = postData.brdno;
        postData.brdEmail = req.session.email;
        postData.replyer = req.session.name;
        postData.reply_text = postData.reply_text;
        doc.set(postData);
        res.json({ message: 'ok' });
    } else { // update
        if (req.session.email != postData.brdEmail && req.session.admined != true) {
            res.json({ message: '수정/삭제는 본인이 작성한 글만 가능합니다.' });
        } else {
            var doc = db.collection("reply").doc(postData.replyno);
            postData.brdEmail = req.session.email;//해킹방지
            postData.replyer = req.session.name;//해킹방지
            doc.update(postData);
            res.json({ message: 'ok' });
        }
    }    
});

router.post('/reply_delete', function (req, res, next) {
    console.log('여기-', req.body.replyno);
    if (!req.session.logined) {
        res.redirect('/board/loginForm');
        return;
    }
    //console.log(req.session.email, '확인', req.body.brdEmail);
    if (req.session.email != req.body.brdEmail && req.session.admined != true) {
        res.json({ message: '수정/삭제는 본인이 작성한 글만 가능합니다.' });
    }else{
        db.collection('reply').doc(req.body.replyno).delete()
        res.json({ message: 'ok' });
    }
});

module.exports = router;

지난번 게시판DB는 파이어베이스 Store의 컬렉션명이 board 였고, 댓글의 컬렉션명은 reply 로 정했습니다.

NoSQL 데이터베이스라서 ERD작업이나 SQL 명령어 없이 테이블(컬렉션)과 레코드(document)필드가 입력데이터로 자동 생성이 됩니다.^^ SQL쿼리 대신 파이어베이스에서 제공하는 query함수로 조회, 입력, 수정, 삭제가 됩니다.

이번 조회를 위한 복합색인1개 + 단일필드 1개로 인덱스 생성(오름차순,내림차순 모두사용)의 게시판 때와는 다르게 복합 색인(Index)만을 2개 생성 했습니다.(아래)

- 위 복합색인은 개발자가 노드js 프로그램 작업 시 조회 화면의 에러 콘솔에 나타난 링크를 클릭하면 쉽게 만들 수 있습니다.(아래 화살표 순서대로)

복합 색인 만드는 과정(위)

 

Ps, 앞으로 게시판 입력 창에 에디터를 붙이는 작업을 할 예정 입니다.

관련글 더보기

댓글 영역