티스토리 뷰

반응형

부제: NOSQL 모듈화 경험기.


 나는 다룰줄 아는 언어가 JAVA 밖에 없다. 그래서 요즘 JavaScript를 열심히 보고 있다 ㅎㅎ. 내 생각에는 JAVA와 JavaScript는 완전히 다른 언어이다. 그리고 굉장히 매력적인 언어라고 생각한다. 내가 프로그래밍 언어를 JavaScript로 접했으면 좋았겠다는 생각도 한다.


 금요일에 휴가도 썼겠다.. 3일간에 뭘 만들어볼까 고민을 해봤는데, 야구선수 데이터를 활용한 간단한 선수 추천 앱같은 것을 만들어보고 싶었다. 그런데 문제는..


KBO는 OPEN API를 제공하지 않는다....


 나는 phantom.js와 같은 고오급 기술은 사용하지 않았다. request, cheerio 모듈을 활용했다. 닭잡는데 소잡는 칼이 나설 필요는 없으니까! ㅎㅎㅎㅎ 다음 소스코드는 크롤링을 하는 부분이다.


var express = require('express');
var router = express.Router();
var kbreport = require('../kbreport');
var database;

var options = {
    headers: {
        'Accept': 'text/*'
    }
};

module.exports = function(app) {
    /* GET users listing. */
    router.get('/kbreport', function(req, res, next) {

        var i = 1;
        var database = app.get('database');
        var interval = setInterval(function(){
            kbreport(database, options, i++);
            if(i >= 1550) { // 1550
                clearInterval(interval);
                console.log('종료');
            }
        },100);
        res.send('성공');
    });

    return router;
};

 서버에 get요청을 보낼 경우 친히 for loop를 돌며(약 1550회) 야구통계 사이트의 모든 페이지를 싹싹 긁어오도록 구현해봤다! 그런데 cheerio를 쓰기 전에... 야구통계 사이트의 선수 상세 페이지가 어떻게 생겨먹었는지 알아봐야했다. 개발자도구를 사용해도 좋지만, 좁아터진 모니터의 압박이 있었다 ㅎㅎ


 그래서 Postman 등판~



 이쁘게 잘 나온다! 중요한 데이터는 table로 되어있는 것도 알게되었고.. 그래서 cheerio-tableparser라는 모듈을 추가로 사용하기로 했다! 크롤링하는 함수가 너무 길다보니 소개는 못할꺼같다.. (페이지를  파싱하기 위한 하드코딩의 향연...)



 데이터를 뽑아내는 것은 성공한 상황에서.. 이제 DB에 넣는 것이 남았다. 기왕 공부삼아 시작한 만큼 mongoDB를 사용해보기로 했다!


 mongoDB를 다룰 때는 스키마와 모델을 잘 정리하는 것이 중요한거 같아서.. 나름 머리를 써서 모듈화를 시켜봤다.


 이런식으로 스키마를 정의한 모듈DB연결을 담당하는 모듈을 따로 나눠봤다. 그리고 config 모듈에 스키마, 모델, 스키마파일에 대한 정보를 관리하도록 했다. 먼저 config.js를 소개한다.


module.exports = {
    serverPort: process.env.PORT || 3000,
    dbUrl: 'mongodb://localhost:27017/BBPlayerDic',
    dbSchemas: [
        {file: '../database/batterStat', collection:'batterStats', schemaName: 'batterStat', modelName: 'batterModel'},
        {file: '../database/pitcherStat', collection:'pitcherStats', schemaName: 'pitcherStat', modelName: 'pitcherModel'}
    ]
};


 별거 없긴하다. 하지만 더 읽어보면 이 부분이 얼마나 중요한지 알 수 있다. 그다음은 스키마를 정의하는 부분이다! batterStat.js와 pitcherStat.js는 비슷하니 batterStat.js만 소개한다.


var schema = {};
schema.createSchema = function (mongoose) {

    var batterStat = mongoose.Schema({

        id: {type: Number, required: true},
        name: {type: String},
        birth: {type: String},
        hand: {type: String},
        position: {type: String},
        team: {type: String},
        salary: {type: Number, default: 0},
        year: {type: Number, default: 0},
        // 중략..
    });

    return batterStat;
};

module.exports = schema;


 mongoose 모듈을 활용하여 스키마를 생성하는 간단한 로직이다. 이렇게 분리를 해놓았으니, 스키마가 혹시 수정되더라도 이 js파일만 고치면 된다. ㅎㅎ


 마지막으로 database.js 파일이다.



var mongoose = require('mongoose');
var database = {};

database.init = function (app, config) {
    connect(app, config);
};

function connect(app, config) {
    // 데이터베이스 연결
    console.log('DB연결을 시도합니다.');
    mongoose.Promise = global.Promise;
    mongoose.connect(config.dbUrl);
    database = mongoose.connection;

    database.on('error', console.error.bind(console, 'mongoose connection error.'));

    database.on('open', function() {
        console.log('데이터베이스에 연결되었습니다.: '+config.dbUrl);
        createSchema(app, config);
    });

    database.on('disconnected', function(){
        console.log('연결이 끊어졌습니다. 5초 후 다시연결합니다.');
        setInterval(connect, 5000);
    });

    function createSchema(app, config) {
        var schemaLen = config.dbSchemas.length;

        for(var i = 0; i < schemaLen; i++) {
            var curItem = config.dbSchemas[i];
            
            // config.js의 createSchema 호출하여 스키마 GET
            var curSchema = require(curItem.file).createSchema(mongoose);
            // config.js의 정보로 model 생성
            var curModel = mongoose.model(curItem.collection, curSchema);
            
            // database 객체에 각각 저장
            database[curItem.schemaName] = curSchema;
            database[curItem.modelName] = curModel;
        }
        // 어디서든 쉽게 꺼내쓰도록..
        app.set('database', database);
    }
}

module.exports = database;

 맨 마지막 createSchema 함수를 주의깊게 보면 되겠다. 흩어져있던 각각의 모듈에서 필요한 정보를 불러와서 DB 스키마 및 모델정보를 생성하고 있다. 이렇게 '관심사'를 분리했다.


database.js의 관심사: DB접근을 가능하도록 하자 (연결 및 모델생성)


batterStat.js의 관심사: 스키마정보를 관리하자


config.js의 관심사: 스키마정보 파일에 대한 정보(파일위치 및 이름)을 관리하자




 완성결과, 위와 같이 데이터가 이쁘게 DB에 저장되었다. 이걸 만드는데 이틀정도 꼬박 고민한거 같다. 대부분 웹페이지 파싱에서 시간을 날려먹었지만..


 나도 멋진(?) 개발자가 되고 싶은데 이렇게 쉬운 것도 헤매고 있어서 고민이 많다. 어떡하면 개발 스킬업을 쑥쑥할 수 있을지..




※ 야구통계사이트의 요청으로 일부 내용이 삭제되었습니다.(2018.03.26)


-끝-



«   2021/12   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
글 보관함
Total
759,125
Today
15
Yesterday
253