### 지난번 댓글 기능을 추가하기 위한 준비를 해 보았습니다. (아래)
현재 작업 중인 소스는 아래 깃 허브에 올려 놓았습니다.(단, 서비스계정키 파일은 보안때문에 제외 시켰습니다.)
-. 표준노드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, 앞으로 게시판 입력 창에 에디터를 붙이는 작업을 할 예정 입니다.
노드js앱을 컨테이너기반 도커용 앱으로 실행하기 (1) | 2024.01.02 |
---|---|
구글파이어베이스를 사용해 노드js 웹서비스 만들기_5/5 (1) | 2023.12.29 |
구글파이어베이스를 사용해 노드js 웹서비스 만들기_3/5 (0) | 2023.12.26 |
구글파이어베이스를 사용해 노드js 웹서비스 만들기_2/5 (0) | 2023.12.25 |
구글파이어베이스를 사용해 노드js 웹서비스 만들기_1/5 (1) | 2023.12.19 |
댓글 영역