스토리지

[07.14] - 해당 챕터를 몇 명의 유저가 클리어 했는지 비율 출력 본문

Node.js

[07.14] - 해당 챕터를 몇 명의 유저가 클리어 했는지 비율 출력

ljw4104 2021. 7. 14. 17:53

디트로이드 비컴휴먼 게임을 보면 선택지마다 몇 명의 사람들이 선택했는지 백분율로 표시해두었다.

클라이언트측에서 계산하면 더 편하지만 모든 유저의 데이터를 다운받아야하는 아주 위험한 행동이기에 서버에서 처리하기로 하였다.

 

동작방식

  1. 알고싶은 엔딩 번호로 서버 URL에 요청을 보낸다.
  2. 일단 모든 유저를 임시로 받아온다. (로컬이기에 함수가 끝나면 자동으로 메모리에서 해제되서 괜찮다.)
  3. 유저들을 탐색하며 해당 엔딩챕터를 클리어한 기록이 있는지 확인한다.
  4. 유저들을 탐색하며 모든 유저를 상대로 해당 변수에 +1을 해주되, 해당 엔딩번호가 존재하면 해당 변수에 +1을 해주었다.
  5. 해당 엔딩을 본 유저의 수 / 모든 유저의 수 * 100, 백분율로 응답을 클라이언트로 보내고 서버는 할 일이 종료.

MongoDB가 지금을 기준으로 14시간 전에 패키지가 싸그리 바꼈다....

원래는 동기 코드로 동작하였지만 공식 패키지도 이제 비동기를 사용하게 되었다.

https://www.npmjs.com/package/mongodb

 

mongodb

The official MongoDB driver for Node.js

www.npmjs.com

 

app.js

require('dotenv').config()
const express = require('express');
const { MongoClient } = require('mongodb')
const app = express();
const port = 3000;

const userDb = 'Users';
const userCollection = 'users';
const uri = process.env.DB_ADDRESS;

app.use(express.json());

app.get('/:chapterNum', (req, res) => {
    let wholeUser = 0;                  //모든 유저의 수
    let num = 0;                        //해당 챕터를 클리어한 유저의 수
    let userDatas = [];                 //모든 유저의 데이터
    const chapterNum = req.params.chapterNum;
    const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
    client.connect(async function (err) {
        if (err) {
            let results = {
                status: 500,
                message: "Cannot connect to database: " + err,
            };
            res.send(results['message']);
        }
        const collection = client.db(userDb).collection(userCollection);

        const findResult = await collection.find({}, { projection: { _id: 0 } }).toArray();
        findResult.forEach((item) => {
            userDatas.push(item);
        });

        userDatas.forEach((item) => {
            wholeUser++;
            if (item['arrEnding'][chapterNum] !== undefined) {
                num++;
            }
        })
        client.close();
        res.send((num / wholeUser * 100).toString());
    });
});

app.listen(port, () => {
    console.log(`Server is running at port:${3000}`);
});

 

현재 DB에 등록된 유저의 수: 2, E12챕터를 클리어한 유저 수: 1

 

 

  1. find() 함수는 Documents 배열을 return한다. 그래서 forEach문을 돌면서 해당 객체들을 옮겨주었다. 지금보면 굳이 옮길 필요없이 바로 하면 될거 같긴하다. 괜히 메모리만 차지했다.
  2. 이제 배열을 순회하면서 chapterNum을 키로 하는 객체가 존재하면 (undefined가 아니면) +1을 해준다.
  3. 그렇게 모든 요소들을 순회 후 계산하여 response를 보낸다.
Comments