728x90
반응형

전 글에서 schemas 파일까지 다루어보았다.

이번 글에선 대망의query.js를 다루어보겠다.

 

1. 전체코드 

const mongoose = require('mongoose');
const { Schema } = mongoose; 

const { WORKER, COLLECTION_NAME, QUERY } = require('../const/consts'); //consts 파일들
      
const Schemas = require('./schemas')

const { Worker } = Schemas; // 몽구스 model 파일들

exports.modelQuery = async (query,collection,doc,option) => {
    var doc = doc;
    
    var Collection = Schemas[collection];
    
    // console.log(Collection.prototype.schema.options.collection);
    
    var option = option;
    var one;
    var postJob; // 임의로 지정해줄 수도 있고, option으로 받아올 수도 있음 (부가적인 함수)
    
    if(option.postJob) {
        postJob = option.postJob;
    }
    
    var resResult = (result) => { //함수가 끝나고 실행되는 콜백함수
      if (postJob != null) {
         postJob();
      }
      return result;
    };
    
    
    if ( query == QUERY.Aggregate) {
        var aggregatearray = [];
        
        switch (collection) {
            case COLLECTION_NAME.Alarm : 
                break;
            case COLLECTION_NAME.Car :
                break;
        }
        
        if(doc != undefined) {
            if (doc.addFields) {
                aggregatearray.push({$addFields : doc.addFields});
            }
            if (doc.lookup) {
                aggregatearray.push({$lookup : doc.lookup});
            }
            if (doc.unwind) {
                aggregatearray.push({$unwind : doc.unwind});
            }
            if (doc.match) {
                aggregatearray.push({$match : doc.match});
            }
            if (doc.project) {
                aggregatearray.push({$project : doc.project});
            }
            if (doc.sort) {
                aggregatearray.push({$sort : doc.sort});
            }
            if (doc.limit) {
                aggregatearray.push({$limit : doc.limit});
            }
        }
        if (Object.keys(option).length != 0) {
            if (option.limit) {
                
            }
            if (option.sort) {
                
            }
        }
        else {
            var one = await Collection.aggregate([aggregatearray]).then(resResult);
        }
        
        return one;
        
    }
};

 

원래는 각 쿼리별 조건문이 다 들어있으나, 결국 방식은 비슷하기 때문에 mongoose의 쿼리문인 aggregate만 예시로 들었다. 방식은 전에 정의해두었던 consts 파일에서 사용할 schema(열거체)와 query, collection_name를 가져오고 모델을 미리 정의해두었던 schema(모델)을 가져온다.

 

그 다음 modelquery 함수를 정의하고, 인자 값을 query, collection, doc, option을 설정해서 어떤 스키마, 어떤 쿼리, 어떤 데이터가 들어오든 쿼리가 실행이 가능하도록 한다.

 

실제로 라우터에선

//Schemas
const {modelQuery} = require('../schemas/query')
const {COLLECTION_NAME, QUERY} = require('../const/consts');

 

이 것만 위에 선언을 해주고

const agents = await modelQuery(QUERY.Findone,COLLECTION_NAME.Company,{ "CNU" : CNU+"000" },{});

 

이방식대로 써주면 JQuery 뿐만 아니라 React.js_node.js(Back-end), Graphql에서도 활용이 가능하다.

NoSQL이 아닌 SQL 또한 node js sequelize를 사용 할 때 모델을 지정해주는 방법만 바꿔주면 활용이 가능하다.

 

이 방법이 성공했을 때 진심으로 전율을 느꼈다..

728x90
반응형

'DB > MongoDB' 카테고리의 다른 글

MongoDB | Schemas(2)  (0) 2021.09.14
MongoDB | Schemas(1)  (0) 2021.09.14
MongoDB | Consts 만들기  (0) 2021.09.14
MongoDB | 설치하기, 삭제하기  (0) 2021.09.14
728x90
반응형

전 글에서 index.js까지 만들어보았다.

이번 글에서는 schemas.js를 다루어보겠다.

 

1. schemas.js

const mongoose = require('mongoose');

const {  WORKER } = require('../const/consts');

const { Schema } = mongoose;


const workerSchema = new Schema(WORKER.schema, { collection: 'Worker' });

const Worker = mongoose.model('Worker',workerSchema);


const COLLECTIONS = {
    "Worker" : Worker
}

module.exports = COLLECTIONS;

 

먼저 mongoose를 require 해주고, 

기존에 consts에 만들어놨던 WORKER를 가져온다.(schema를 쓰기위해)

 

그다음 mongoose에서 Schema를 가져오고,

 

해당 스키마의 인스턴스를 만들어준다 ( collection 네임과 const 안의 collection_name이 동일해야 합니다. )

 

그다음 Worker라는 모델을 생성해준 후

나중에 query.js에서 쓰기위해 COLLECTIONS에 담아주고 exports 해줍니다. 

728x90
반응형

'DB > MongoDB' 카테고리의 다른 글

MongoDB | Schemas(3)  (0) 2021.09.14
MongoDB | Schemas(1)  (0) 2021.09.14
MongoDB | Consts 만들기  (0) 2021.09.14
MongoDB | 설치하기, 삭제하기  (0) 2021.09.14
728x90
반응형

먼저 이 모듈화를 시작하게 된 계기는 라우터마다 사용할 스키마를 가져오는것이 불편하다 느꼈고, 이를 어떤 상황이라도 모든 쿼리문이 모든 스키마에 적용되도록 설계를 해보게 되었다.

이 방식을 쓰면 모든 라우터에 

//Schemas
const {modelQuery} = require('../schemas/query')
const {COLLECTION_NAME, QUERY} = require('../const/consts');

이와같이 두줄만 쓰면 모든 쿼리문을 사용가능하다. 또한 스키마별로 파일을 생성하지 않아도 되며, 라우터에서 쓰일 열거체들은  const에 스키마와 같이 정의하여 훨씬 깔끔하게 mongo query를 사용할 수 있다.

 

먼저 mongoose를 설치하고, express파일에서 connect를 실행하게끔 하고  index.js파일부터 정의해보자.

sudo npm i mongoose

 

1. 파일 구조

/root
└schemas
 └index.js
 └query.js
 └schemas.js

 

2. index.js

require('dotenv').config();
const mongoose = require('mongoose');

const connect = () => {
    // const mongoCon = 'mongodb://test:test1234@18.140.74.102:9003/admin';
    const mongoCon = 'mongodb://'+process.env.MONGO_ID+':'+process.env.MONGO_PWD+'@'+process.env.MONGO_IP+':'+process.env.MONGO_PORT+'/admin';
    
    if (process.env.NODE_ENV !== 'production') {
        mongoose.set('debug', true);
    }
    mongoose.connect(mongoCon, {dbName: 'OASIS'}, {
    }, (error) => {
        if (error) {
            console.log('DB Connection is Error', error);
        }
        else {
            console.log('DB Connect is SuccessFul!');
        }
    });
};
mongoose.connection.on('error', (error) => {
    console.error('DB Error', error);
});
mongoose.connection.on('disconnected', () => {
    console.error('DB is disconnected, Continue to Connect DB');
    connect();
});

module.exports = connect;

mongoDB에 관한 내용들은 env파일에 담아두었다.

728x90
반응형

'DB > MongoDB' 카테고리의 다른 글

MongoDB | Schemas(3)  (0) 2021.09.14
MongoDB | Schemas(2)  (0) 2021.09.14
MongoDB | Consts 만들기  (0) 2021.09.14
MongoDB | 설치하기, 삭제하기  (0) 2021.09.14
728x90
반응형

1. 파일구조

/root
└const
 └consts.js
 └collection_name.js
 └query.js
 └worker.js

 

2. worker.js - 라우터에서 쓰일 열거체와, mongoose에서 쓰일 schema를 정의한다.

const WORKER = {
    "CNU" : "CNU",
    "WN" : "WN",
    "PN" : "PN",
    "GID" : "GID",
    "EM" : "EM",
    "PU" : "PU",
    "CA" : "CA",
    "UA" : "UA",
    
    schema : {
        CNU: { // Company Number
            type: String,
            required: true,
        },
        WN: { // Worker Name
            type: String,
            required: true,
        },
        PN: { // Phone Number
            type: String,
            unique: true,
        },
        GID:{   // Google Account ID
          type: String,
        },
        EM: { // Email
            type: String,
            unique: true,
            required: true,
        },
        PU: { // Photo URL
            type: String,
        },
        CA: { // Created At
            type: Date,
            default: Date.now,
        },
        UA: { // Updated At
            type: Date,
            default: Date.now,
        }
    }
}

exports.WORKER = WORKER;

 

3. query.js - modelquery 함수에서 쓰일 query문 열거체들을 정리한다.

const QUERY = {
    
    Aggregate : "aggregate",
    Create : "create",
    InsertMany : "insertmany",
    Find : "find",
    Findone : "findone",
    Update : "update",
    Updatemany : "updatemany",
    Updateone : "updateone",
    Updateupsert : "updateupsert",
    Remove : "remove",
    Count : "count",
    CountDoc : "countdoc",
    Distinct : "distinct"
    
};

exports.QUERY = QUERY;

 

4. collection_name.js - 사용할 collection 이름들을 정리한다.

const COLLECTION_NAME = {
    "Worker" : "Worker"
}

exports.COLLECTION_NAME = COLLECTION_NAME;

 

5. consts.js - 한곳에서 import 하기위해 위에 모든 것들을 담는 js파일을 만들어준다.

const {WORKER} = require('../const/worker');
const {COLLECTION_NAME} = require('../const/collection_name');
const {QUERY} = require('../const/query');


exports.WORKER = WORKER;
exports.COLLECTION_NAME = COLLECTION_NAME;
exports.QUERY = QUERY;
728x90
반응형

'DB > MongoDB' 카테고리의 다른 글

MongoDB | Schemas(3)  (0) 2021.09.14
MongoDB | Schemas(2)  (0) 2021.09.14
MongoDB | Schemas(1)  (0) 2021.09.14
MongoDB | 설치하기, 삭제하기  (0) 2021.09.14
728x90
반응형

1.     몽고DB의 public GPG key 주입

ubuntu@dev:~$ wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -

OK

 

2.     몽고DB를 위한 리스트 파일 생성

ubuntu@dev:~$ echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list

 

 

3.     로컬 패키지 데이터베이스 갱신

ubuntu@dev:~$ sudo apt-get update

 

 

4.     몽고DB 설치

ubuntu@dev:~$ sudo apt-get install -y mongodb-org

 

 

5.     몽고 서비스 실행

ubuntu@dev:~$ sudo service mongod start

 

6. 관리자 계정 추가

MongoDB에 다시 접속하여 관리자 계정을 추가한다.

 

$ mongo

 

>use admin

db.createUser({            

    user: “유저아이디" ,            

    pwd: “패스워드",            

    roles: [‘root’]

})

 

uncaught exception: Error: couldn't add user: command createUser requires authentication :

해당 오류가 뜬다면 이는 /etc/mongod.conf에서 security.authorization이 true로 설정되어 있기 때문이었다.
책에서 사용하던 버전에서는 원래 주석처리되어 있었는지 이후에 추가하도록 되어있는데, 이번에 설치한 4.2.9 버전에서는 처음부터 작성되어 설치되어서 문제가 되었다.

잠깐 주석 처리하고 sudo service mongod restart하니 정상적으로 admin 사용자를 추가할 수 있었다

 

 

 

7. 인증 설정

MongoDB에 접속할 때 인증과정이 이루어지도록 설정파일을 수정한다.

우선 MongoDB를 종료한 후 수정을 한다.

ubuntu@dev:~$ sudo service mongod stop

ubuntu@dev:~$ sudo vim /etc/mongod.conf

 

mongod.conf 설정파일의 security 항목의 주석을 해제한 후 그 하단에 authorization: enabled 를 추가한다.

security:

  authorization: enabled

 

8. 인증 접속

MongoDB를 다시 실행한 후 등록한 계정 정보로 접속을 시도해 보자.

ubuntu@dev:~$ sudo service mongod start

ubuntu@dev:~$ mongo admin -u test -p test1234

 

 

9. 외부 접속 설정

MongoDB는 기본적으로 로컬호스트에서만 접속이 가능하도록 설정되어 있다. 외부 접속을 위해서는 net 항목의 bindIp 항목을 0.0.0.0으로 변경한다. (포트도 변경 가능)

net:

  port: 27017

  bindIp: 0.0.0.0

 

10. 몽고 DB 삭제 방법

sudo apt-get remove mongodb-org

sudo apt-get purge mongodb-org*

sudo rm -rf /var/log/mongodb

sudo rm -rf /var/lib/mongodb
728x90
반응형

'DB > MongoDB' 카테고리의 다른 글

MongoDB | Schemas(3)  (0) 2021.09.14
MongoDB | Schemas(2)  (0) 2021.09.14
MongoDB | Schemas(1)  (0) 2021.09.14
MongoDB | Consts 만들기  (0) 2021.09.14
728x90
반응형

1. 먼저 화면 구성을 해준다. 버튼을 눌렀을 경우 onclick으로 함수가 실행되도록 한다.(로그아웃도 동일)

 

 

2. HTML script - get메소드를 쓰기 때문에 location 을 바꿔주어서 백엔드에서 로직이 실행되도록 한다.

// 회원탈퇴 기능
function withdrawal(i18nconvert) {
	var answer;
	//페이지를 이동하기 전에 confirm()을 사용해 다시 한번 확인한다.
	//확인을 선택하면 answer에  true, 취소를 선택하면 false 값이 들어간다.
	answer = confirm(i18nconvert("layout_withdrawal_confirm"));
	//확인을 선택한 경우 자바스크립트를 호출할 때 같이 넘어온 url이라는 변수에 들어있는 주소로 페이지 이동
	if(answer == true){
		location = '/auth/withdrawal';
	}
	else {
		return false;
	}
}

// 로그아웃 기능
function logout(i18nconvert) {
	var answer;
	//페이지를 이동하기 전에 confirm()을 사용해 다시 한번 확인한다.
	//확인을 선택하면 answer에  true, 취소를 선택하면 false 값이 들어간다.
	answer = confirm(i18nconvert("layout_signout_confirm"));
	//확인을 선택한 경우 자바스크립트를 호출할 때 같이 넘어온 url이라는 변수에 들어있는 주소로 페이지 이동
	if(answer == true){
		location = '/auth/logout';
	}
	else {
		return false;
	}
}

 

 

3. 백엔드쪽에서 로그아웃은 쿠키가 삭제되도록, 회원탈퇴는 DB에서 데이터가 삭제되도록 한다.

//logout시 Browser Cookie 삭제
router.get("/logout", async function( req, res, next){
  try {
    await res.cookie("token", req.cookies,{expiresIn:0});
    res.redirect("/");
  } catch(err){
    console.error(err);
    next(err);
  }
});

//withdrawal시 Browser Cookie 삭제 하고 소독이력을 제외한 company에 관련된 내용들 삭제
router.get("/withdrawal", isNotLoggedIn, async function(req, res, next){
  const CID = req.decoded.CID;
  const CNU = req.decoded.CNU;
  
  try {
    await modelQuery(QUERY.Remove,COLLECTION_NAME.Company,{"_id": CID},{});
    await modelQuery(QUERY.Remove,COLLECTION_NAME.Car,{"CNU": CNU},{});
    await modelQuery(QUERY.Remove,COLLECTION_NAME.Device,{"CNU": CNU},{});
    await modelQuery(QUERY.Remove,COLLECTION_NAME.Worker,{"CNU": CNU},{});

    await res.cookie("token", req.cookies, { expiresIn : 0 });
    
    res.redirect("/");

  } catch(err){
    console.error(err);
    next(err);
  }
});
728x90
반응형
728x90
반응형

1. 먼저 nunjucks를 설치해준다.

npm install nunjucks

 

2. express와 nunjucks를 연결해준다.

// app.js
const express = require('express');
const app = express();

app.set('port', process.env.PORT || 3000);
app.set('view engine', 'html')
nunjucks.configure('views', {
  express: app, 
  watch: true, 
});

const indexRouter = require('./routes/index');
app.use('/', indexRouter);

 

3. 라우터에 사용할 변수를 페이지에 렌더링해준다.

const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.locals.title = 'Express'
  res.render('index')
});

module.exports = router;

 

4. 최상위 html 파일에 넌적스 변수를 선언해준다.

// layout.html
<!DOCTYPE html>
<html>
  <head>
    <title>{{title}}</title>
    <link rel="stylesheet" href="/style.css" />
  </head>
  <body>
    {% block content %}
    {% endblock %}
  </body>
</html>

// index.html
{% extends 'layout.html' %}

{% block content %}
<h1>{{title}}</h1>
<p>Welcome to {{title}}</p>
{% endblock %}

 

 

이렇게 하면 백엔드에서 넘겨준 변수를 html에서 쓸 수 있다. {{ }} 이걸로 변수를 감싸주면 끝!

{% %} 이런 형식으로 변수를 이용한 반복문, 또다른 변수선언 등을 할 수도 있다.

728x90
반응형
728x90
반응형

※ 지점, 본사는 무시하셔도 됩니다.

 

먼저 사업자등록번호(아이디)를 입력한 후 존재하면 해당 정보에 등록된 이메일 주소가 일부 가려진 채로

나오게 되고 (혹시나 이메일 주소를 잊었을 경우), 이메일 주소를 입력하고 버튼을 누르면 전송이 되게끔 하였다.

(이메일 보내기는 회원가입 글을 확인 부탁드립니다) 이후에 이메일을 보내는 부분은 회원가입을 했을 경우랑 같고, 

바뀐 임의의 비밀번호를 이메일 주소로 보내게끔 하였으며, 사이트 내에 프로필 수정 화면을 통해 비밀번호를

변경할 수 있도록 했다.

728x90
반응형
728x90
반응형

1. 미들웨어는 이런식으로 사용이 된다.

// 로그인
router.get('/login', isLoggedIn, (req, res) => {
  res.render('login');
});

 - 라우터가 실행될 때, 그전에 먼저 실행되서 어떻게 할건지를 설정해준다. ( 예를들어 로그인이 안되어있을 경우 이런 페이지로 가겠다. ) 사실 라우터마다 설정들을 다 해줄 순 있지만, 굳이 반복되는 코드를 여러번 쓰는것보단 미들웨어로 한번에 처리하면 사용하기에도 편리하다.

 

먼저, middleware.js라는 파일을 만들고 exports 되는 함수들을 정의한 다음에

const { isLoggedIn, isNotLoggedIn, DataSet, agentDevide } = require('./middleware');

이런 식으로 미들웨어 사용이 필요한 라우터 마다  require로 정의를 해주었다.

 

 

 

2. 나는 이런식으로 로그인이 될 경우에 메인화면으로 오게 만들었고,

exports.isLoggedIn = (req, res, next) => {
  try {
    req.decoded = jwt.verify(req.cookies.token, secretObj.secret);
    res.redirect('/main');
  } catch(err) {
    next();//Token 만료시 다시 로그인 페이지로 넘어가게 설정
  }
};

 

3. 모든 페이지마다 로그인이 안되어있을 경우에 루트 페이지로 가도록 설정했다.

exports.isNotLoggedIn = (req, res, next) => {
  try {
    req.decoded = jwt.verify(req.cookies.token, secretObj.secret);
    next();   
  } catch(err) {
    res.redirect('/') ;//Token 만료시 다시 로그인 페이지로 넘어가게 설정
  }
};
728x90
반응형
728x90
반응형

화면 구성

※ 본사 지점은 무시하셔도 됩니다.

 

1. html 코드

 기본적으로 사업자번호(아이디)와 비밀번호를 입력하도록 설계하였다.

<form action="" method="post" id="login-form2" class="margin-bottom-0" onsubmit="login('login-form2','CNU2','ANA2','PW2');">
<!--사업자번호-->
  <div class="form-group m-b-20">
  <input id="CNU2" name = "CNU2" type="text" class="form-control form-control-lg inverse-mode" placeholder="{{__('business_number')}}" required />
  </div>
<!--비밀번호-->
  <div class="form-group m-b-20">
  <input id="PW2" name = 'PW2' type="password" class="form-control form-control-lg inverse-mode" placeholder="{{__('pw')}}" required />
  </div>
<!--버튼-->
  <div class="login-buttons">
  <button type="submit" class="btn btn-primary btn-block btn-lg">{{__('login')}}</button> 
  <li class="form-control-lg inverse-mode"><a href="/register" >{{__('signup')}}</a>   /  <a href="/find" > {{__('findpw')}}</a></li>
  </div>
</form>

 

2. script부분에서 input을 parsley로 형식을 검사한 후에 loginAjax를 실행하도록 하였다.

function login(form, companyNumber, agentInfo, password) {
    var CNU = document.getElementsByName(companyNumber)[0].value;
    var ANU = document.getElementsByName(agentInfo)[0].value.split("/")[0];
    var ANA = document.getElementsByName(agentInfo)[0].value.split("/")[1];
    var PW = document.getElementsByName(password)[0].value;
    var validateCNU = $('#'+form).parsley();

    if(validateCNU.isValid() == true) {
    	loginAjax(CNU,ANU,ANA,PW);
    }
    event.preventDefault();
  }

 

3. loginAjax() 함수로 백엔드에 데이터를 보낸 후 성공할 경우 어떻게 할건지를 정의한다.

// 로그인 기능
function loginAjax(companyNumber, agentNumber, agentName, password) {
	$.ajax({
		type: 'POST',
		url: 'auth/login',
		dataType: 'json',
		data: {
			CNU: companyNumber,
			ANU: agentNumber,
			ANA: agentName,
			PW: password
		}
	}).done(function(data) {
		if(data.result == 'success') {
			location = '/main';
		}
		else if(data.result == 'fail') {
			alert(i18nconvert('login_error'));
		}
		else {
			alert(i18nconvert('login_fail'));
		}
	});
}

 

3. 백엔드쪽에서 올바른 데이터가 들어왔을 경우 로그인 정보를 쿠키에 담아준다.

//login 진행 할경우 토큰 만들어서 cookie에 넣음
router.post("/login", async(req, res, next) => {
  const {CNU, ANU, ANA, PW} = req.body;
  try {
    const company = await modelQuery(QUERY.Findone,COLLECTION_NAME.Company,{ "CNU" : CNU+ANU, "ANA" : ANA, "ANU" : ANU },{});// CNU에 맞는 데이터 찾아오기
    if(company) {
      //bcrypt 암호화된 PW와 입력 PW 비교
      if(bcrypt.compareSync(PW, company.PW) ){
        const token = jwt.sign({ CNU : company.CNU, ANU : company.ANU, ANA : company.ANA, CNA : company.CNA, CID : company._id, AH : company.AH },// 토큰의 내용(payload)
          secretObj.secret,   // 비밀 키
          { expiresIn: '1440m' });  // 유효 시간은 1440분 하루 설정
        res.cookie("token", token); // 쿠키에 token 등록
        
        return res.send({ result : 'success' });
      }
      else{
        return res.send({ result : "fail" });
      }
    }
    else {
      return res.send({ result : "fail" });
    }
  } catch(err){
    res.send({ result : "fail" });
    console.error(err);
    next(err);
  }
});

 

 

페이지마다 미들웨어를 설정해서 로그인된 정보가 쿠키에 없을 경우에 로그인 화면이나 원하는 화면으로 돌아가도록

설정을 해주면 좋다!

728x90
반응형

+ Recent posts