궤도

[백엔드] Node.js + Sequelize + MySQL 상세보기 페이지를 만들어보자 본문

💻 현생/📃 VIVA

[백엔드] Node.js + Sequelize + MySQL 상세보기 페이지를 만들어보자

영이오 2021. 2. 9. 16:32

우리의 앱에선 오답노트를 클릭하면

 

이렇게 노트에 있는 문제들을 하나하나 볼 수 있다. 보다시피 문제 삭제 기능도 있다.

 

프론트에서는 사용자의 아이디인 stu_id와 선택한 오답노트의 pk인 note_sn을 넘겨줄 것이다.

 

그럼 나는 해당 오답노트의 페이지들을 하나하나씩 반환해야 한다. 페이지는 문제, 답, 풀이로 구성되어 있으며 페이지네이션을 하려면 전체 문제 수도 넘겨줘야 하고 현재 문제가 몇 번째 문제인지도 알려줘야 한다.

그리고 각 문제들에 대한 삭제 기능도 구현해야 한다


오답노트 페이지

내가 넘겨줘야 하는 정보들을 다시 정리해보자

1. 노트 이름

2. 전체 문제 수

3. 현재 문제가 몇 번째 문제인지

4. 문제 이미지

5. 답안

6. 풀이 이미지

 

뭐가 많은 것 같지만 할 수 있다.

왜이렇게 화질이 깨지는지 모르겠지만 이 테이블들을 쓸 것이다.

 

routes/incor-note-content.js(문제 열람)

//오답노트 문제 가져오기
//localhost:3001/api/incor-note-content/0?note_sn=1&stu_id=samdol
router.get('/:pb', async function (req, res, next) {
    const pb = req.params.pb;

    let result = await models.student.findOne({
        where: {
            stu_id: req.query.stu_id
        }
    });
    const user = result.dataValues.stu_sn;

    //노트 이름
    let title = await models.incor_note.findOne({
        where: {
            note_sn: req.query.note_sn
        }
    });

    //전체 문제 수
    let pbCount = await models.incor_problem.count({
        where: {
            note_sn: req.query.note_sn,
            stu_sn: user
        }
    });

    //문제가 없으면 null 상태 반환
    if (pbCount == 0) {
        res.send({
            message: 'No data',
            status: 'null'
        });
        return;
    }

    //문제들
    let problems = await models.incor_problem.findAll({
        where: {
            note_sn: req.query.note_sn,
            stu_sn: user
        }
    });

    //문제 이미지
    let pb_img = await models.problem.findOne({
        attributes: ['pb_img'],
        where: {
            pb_sn: problems[pb].dataValues.pb_sn
        }
    });

    //답 정보(답안, 풀이 이미지)
    let sols = await models.solution.findOne({
        attributes: ['sol_ans', 'sol_img'],
        where: {
            sol_sn: problems[pb].dataValues.sol_sn
        }
    });

    //문제 정보 : 노트이름, 전체 문제 수, 지금 문제가 몇번째 문제인지, 문제 이미지, 답안, 답 이미지
    const pbInfo = {
        title: title.dataValues.note_name,
        total_pb: pbCount,
        now_pb: pb,
        pb_img: pb_img.dataValues.pb_img,
        sol_ans: sols.dataValues.sol_ans,
        sol_img: sols.dataValues.sol_img
    }

    try {
        res.send({ //교재 정보 넘김
            message: "problem information",
            status: 'success',
            data: {
                pbInfo
            }
        });
    } catch (err) { //무언가 문제가 생김
        res.send({
            message: "ERROR",
            status: 'fail'
        })
    }
});

하나하나 뜯어보자

 

const pb = req.params.pb;

일단 .../0, .../1 이런식으로 페이지를 넘기는게 일반적이니까 현재 문제를 req.params로 받았다.

 

    let result = await models.student.findOne({
        where: {
            stu_id: req.query.stu_id
        }
    });
    const user = result.dataValues.stu_sn;

이건 늘상하는 id를 pk인 sn으로 바꾸는 과정이다.

 

    //노트 이름
    let title = await models.incor_note.findOne({
        where: {
            note_sn: req.query.note_sn
        }
    });

note_sn을 받아왔으니 incor_note 테이블에 가서 노트의 이름을 받아오자.

 

    //전체 문제 수
    let pbCount = await models.incor_problem.count({
        where: {
            note_sn: req.query.note_sn,
            stu_sn: user
        }
    });

    //문제가 없으면 null 상태 반환
    if (pbCount == 0) {
        res.send({
            message: 'No data',
            status: 'null'
        });
        return;
    }

오답노트의 문제 수를 incor_problem에서 받아와서 pbCount에 저장한다. 만약 pbCount가 0이라면 문제가 없다는 것이니 바로 리턴한다. 애시당초 문제가 없으면 클릭조차 안되지 않나?라고 생각할 수 있겠으나, 문제가 1개 남았을 때 그 문제를 삭제하여 0개가 되는 경우가 있기 때문에 넣어주는 것이다.

 

라잌댓

 

    //문제들
    let problems = await models.incor_problem.findAll({
        where: {
            note_sn: req.query.note_sn,
            stu_sn: user
        }
    });

문제들도 받아오자. 아까 count로 실행한걸 findAll로 실행했을 뿐이다.

 

여기까지 했다면 DB 상으로 보았을 때

여기까지 불러온 셈이다.

 

프론트로부터 현재의 문제 번호를 pb로 받아온 것을 기억하는가?

    //문제 이미지
    let pb_img = await models.problem.findOne({
        attributes: ['pb_img'],
        where: {
            pb_sn: problems[pb].dataValues.pb_sn
        }
    });

    //답 정보(답안, 풀이 이미지)
    let sols = await models.solution.findOne({
        attributes: ['sol_ans', 'sol_img'],
        where: {
            sol_sn: problems[pb].dataValues.sol_sn
        }
    });

problems 배열의 pb번째 데이터에 대해 문제 이미지, 답안, 풀이 이미지를 가져오자.

 

    //문제 정보 : 노트이름, 전체 문제 수, 지금 문제가 몇번째 문제인지, 문제 이미지, 답안, 답 이미지
    const pbInfo = {
        title: title.dataValues.note_name,
        total_pb: pbCount,
        now_pb: pb,
        pb_img: pb_img.dataValues.pb_img,
        sol_ans: sols.dataValues.sol_ans,
        sol_img: sols.dataValues.sol_img
    }

그리고 pbInfo에 지금까지 불러온 정보들을 전부 저장한다.

 

    try {
        res.send({ //교재 정보 넘김
            message: "problem information",
            status: 'success',
            data: {
                pbInfo
            }
        });
    } catch (err) { //무언가 문제가 생김
        res.send({
            message: "ERROR",
            status: 'fail'
        })
    }

넘겨주자

 

localhost:3001/api/incor-note-content/0?note_sn=1&stu_id=samdol

 

localhost:3001/api/incor-note-content/1?note_sn=1&stu_id=samdol

각 페이지들의 정보가 잘 나오는 것을 볼 수 있다.


오답노트 문제 삭제

문제 삭제는 상대적으로 간단하다. 넘겨줄 정보도 딱히 없고 삭제만 하면 된다.

 

routes/incor-note-content.js(문제 삭제)

//오답노트 문제 삭제하기
//localhost:3001/api/incor-note-content/0?note_sn=1&stu_id=samdol
router.delete('/:pb', async function (req, res, next) {
    const pb = req.params.pb;

    let result = await models.student.findOne({
        where: {
            stu_id: req.query.stu_id
        }
    });
    const user = result.dataValues.stu_sn;

    //문제들
    let problems = await models.incor_problem.findAll({
        where: {
            note_sn: req.query.note_sn,
            stu_sn: user
        }
    });

    //문제 삭제
    models.incor_problem.destroy({
        where: {
            incor_pb_sn: problems[pb].dataValues.incor_pb_sn
        }
    })
        .then(num => {
            if (num == 1) { //성공
                res.send({
                    message: "Delete problem",
                    status: 'success'
                });
            } else { //데이터 입력을 잘못한듯
                res.send({
                    message: "Data was not found!",
                    status: 'fail'
                });
            }
        })
        .catch(err => { //에러
            res.send({
                message: "Could not delete problem",
                status: 'fail'
            });
        });
});

윗 부분과 중복되는 부분을 빼면 설명할 것이 거의 없다. 그냥 해당하는 문제를 incor_problem에서 삭제하면 된다.

 

localhost:3001/api/incor-note-content/1?note_sn=1&stu_id=samdol

 

해당 주소를 다시 get으로 접근하면

원래 3번째였던 문제가 2번째에 위치하게 됐음을 알 수 있다.

Comments