개발/Node.js

Postgre와 nodejs(Express.js) 연동 - 2 (모듈화 및 데이터 추출)

개발자 솜 2021. 11. 15. 14:29

앞서 1 코드에서 폴더명을 바꾸었다. config-> db

그리고 db.js를 config.js로 바꾸었다.

이런 형태이다.

 

1. config.js를 모듈화 하기

const { Pool } = require('pg')

const pool = new Pool(
    {
        host: process.env.POSTGRE_HOST, 
        user: process.env.POSTGRE_USER,
        password: process.env.POSTGRE_PW,
        port: process.env.POSTGRE_PORT,
        database: process.env.POSTGRE_DB
    }
)

module.exports = {
    query: (text, params, callback) => {
      return pool.query(text, params, callback)
    },
  }

모듈을 추출하여 다른 js에서도 사용하기 위해 module.exports를 추가 작성하였다. return 값을 pool.query로 지정해주어야만 한다.

 

참고 : https://node-postgres.com/guides/project-structure

 

Suggested Project Structure

Whenever I am writing a project & using node-postgres I like to create a file within it and make all interactions with the database go through this file. This serves a few purposes: Allows my project to adjust to any changes to the node-postgres API withou

node-postgres.com

 

 

2. query 메서드를 호출하여 값 가져오기

routes> index.js 

var express = require('express');
var router = express.Router();
let db = require('../db/config')

/* GET home page. */
router.get('/', function(req, res, next) {
  
  db.query('SELECT * from student', (err, res) => {
    if(err) {
      return next(err)
    }
    
    console.log(res.rows)
  })
  
});

module.exports = router;

세번째 줄에 config.js 모듈을 db라는 변수에 할당하였다.

 

결과값

결과값이 잘 호출됨을 알 수 있다.

 

이 형태로 사용해도 무방하지만, routes / index.js 가 엄청 길어지고 가독성이 떨어질 것이다.

그래서 쿼리문만 모아둔 js(db.query부분) 를 따로 만들어 코드를 모듈화 해볼 것이다.

 


모듈화

 

1. 폴더 db 밑에 index.js 생성

 

2. db/index.js 쿼리 작성

let db = require('./config')

// student 개수를 반환하는 메서드
async function getStudentCount() {
    let query = 'SELECT COUNT(*) FROM student' 

    let result = await db.query(query) // 쿼리 실행
    console.log(result.rows[0].count) // 5

    /* 이렇게 가져오는 방법도 있음 (위에 것과 같은 결과를 반환한다.) */
    // let {rows} = await db.query(query) 
    // console.log(rows[0].count)

    let data = result.rows[0].count // 5
    
    return data
}

// student row들을 리턴하는 메서드
async function getStudentInfo() {
    let query = 'SELECT * FROM student'
    let data = [] // 배열 만듦
    let { rows } = await db.query(query)

    for(let row of rows){ // 배열안에 각각의 객체 삽입
        let node = {
            'idx' : row['idx'],
            'name' : row['name'],
            'age' : row['age'],
            'grade' : row['grade'],
        }
        data.push(node)
    }

    console.log(JSON.stringify(data))
    // [{"idx":1,"name":"김똘똘","age:":10,"grade":"B"},{"idx":2,"name":"이장님","age:":9,"grade":"A"},{"idx":3,"name":"홍길동\r\n","age:":11,"grade":"C"},{"idx":4,"name":"윤뽀뽀","age:":10,"grade":"A"},{"idx":5,"name":"박박","age:":9,"grade":"D"}] 
    return data
}


module.exports = {
    getStudentCount,
    getStudentInfo
}

첫번째 줄에 추출했었던 config.js 를 db라는 이름으로 선언했다.

 

db.query는 promise 함수를 사용하기 때문에 await & async를 잘 사용해주어야 한다.

잘 사용하지 않으면  Promise { <pending> } 이라는 결과값이 뜬다. (메서드와 관련 모든 함수에 관련 키워드를 붙여주어야 한다.)

getStudentCount()는 student의 개수를 반환하는 메서드이다.
result.rows[0].count 이렇게 가져오는 이유는 반환 값이 아래와 같은 형태 이기 때문이다.
 

Result {
  command: 'SELECT',
  rowCount: 5,
  oid: null,
  rows: [
    {count : '5' }
  ],
  fields: [
    Field {
      name: 'idx',
      tableID: 16591,
      columnID: 1,
      dataTypeID: 23,
      dataTypeSize: 4,
      dataTypeModifier: -1,
      format: 'text'
    },

...

}

 

getStudentInfo()는 student 테이블의 모든 데이터를 가져온다.
data라는 배열을 만들고 그 안에 
[
   {
      "idx":1,
      "name":"김똘똘",
      "age:":10,
      "grade":"B"
   },
   {
      "idx":2,
      "name":"이장님",
      "age:":9,
      "grade":"A"
   },
   {
      "idx":3,
      "name":"홍길동",
      "age:":11,
      "grade":"C"
   }
...
]

이러한 JSON 형태로 만들어 data를 컨트롤러에 반환해준다. 이제 컨트롤러를 보자.

 

routes/index.js

var express = require('express');
var router = express.Router();
let db = require('../db/index')

/* GET home page. */
router.get('/', async function(req, res, next) {

  const count = await db.getStudentCount();
  console.log('in controller : '  + count) // 5

  const data = await db.getStudentInfo();
  console.log('in controller : '  + data)

  res.render('index', {count: count, data: data})
});

module.exports = router;

세번째 줄에 db/index.js의 모듈을 사용하기 위해 선언하였고,

async, await 처리를 해주었다. 또한 getStudentCount()의 반환값을 count 라는 변수로 받았고

getStudentInfo()의 JSON 객체를 data라는 변수에 담았다.

 

in controller 콘솔 화면

올바른 값이 출력됨을 알 수 있다.

그 두 값(count, data)을 res.render를 통해 index.ejs 로 넘겨주었다.

 

views/index.ejs

<!DOCTYPE html>
<html>
  <head>
    <title>index</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css' />
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
  </head>
  <body>
    <!-- <h1><%= JSON.stringify(data) %></h1> -->
    <h1><%= count %></h1>
    <table class="table">
      <thead>
        <tr>
          <th scope="col">idx</th>
          <th scope="col">name</th>
          <th scope="col">age</th>
          <th scope="col">grade</th>
        </tr>
      </thead>
      <tbody>
        <% for(let i=0; i<data.length; i++){ %>
          <tr>
              <th scope="row"><%= data[i].idx%></th>
              <td><%= data[i].name %></td>
              <td><%= data[i].age %></td>
              <td><%= data[i].grade %></td>
          </tr>
        <% } %>
      </tbody>
    </table>
  </body>
</html>

빠르게 table을 만들기 위해 bootstrap을 이용하여 만들었다. 위에 세가지 cdn을 똑같이 작성해야 한다.

for 반복문을 이용하여 data의 모든 객체를 추출하였다. 

 

결과화면

결과

결과가 잘 나옴을 확인 할 수 있다.

 

 

관련 소스 : https://github.com/datoybi/blog-posting/tree/main/postgre-connect2

 

GitHub - datoybi/blog-posting: code examples posted on my blog

code examples posted on my blog. Contribute to datoybi/blog-posting development by creating an account on GitHub.

github.com