티스토리 뷰

  • created : 2020-06-06

Store Model

// Models/storeModel.js
module.exports = (sequelize, DataTypes) => {
    return sequelize.define('Store',{
        id: { // PK
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true
        },
        name:{ // 가게 이름
            type: DataTypes.STRING(50),
        },
        latitude:{ // 가게 위도
            type: DataTypes.DOUBLE,
            allowNull: false,
        }, 
        longitude:{ // 가게 경도
            type: DataTypes.DOUBLE,
            allowNull: false,
        },
        distance:{ // 가게 거리
          type: DataTypes.DOUBLE,
        },
    }, {
        freezeTableName: true,
        paranoid : true,
    });
};

store Router

const express = require('express');
const router = express.Router();
const storeController = require('../Domain/Store/controller');
const middleware = require('../module/middleware');

router.post('/readAll', storeController.readAll); // 반경 내 가게 조회
module.exports = router;
  • Router에서 request를 받고 request에 맞는 Controller를 호출한다.

store Controller

const StoreService = require('./service');

const rm = require('../../module/util/responseMessage');
const utils = require('../../module/util/utils');
const sc = require('../../module/util/statusCode');
const loc = require('../../module/location');

module.exports = {
  readAll: async (req, res) => {
        // [1]
    **const {
      latitude,
      longitude,
      radius,
    } = req.body;
        // [2]**
    if (!latitude || !longitude || !radius) {
      const missParameters = Object.entries({
        latitude,
        longitude,
        radius,
      })
      .filter(it => it[1] == undefined).map(it => it[0]).join(',');
      res.status(200).send(utils.successFalse(sc.BAD_REQUEST, `${rm.NULL_VALUE}, ${missParameters}`));
      return;
    }
        // [3]
    **await StoreService.readAll({
      latitude,
      longitude,
      radius,
    })**
      .then(({
        json
      }) => res.status(200).send(json))
      .catch(err => {
        res.status(200).send(utils.successFalse(sc.INTERNAL_SERVER_ERROR, rm.INTERNAL_SERVER_ERROR));
      });
  },
}
  1. 정보는 req.body에서 얻어온다.
  2. req 에서 받아온 값들의 유효성 검사를 해준다.
    • 값이 undefinde이라는 것은 값이 넘어오지 않았음을 의미한다.
    • BAD REQUEST를 의미하는 상태코드 404와 빠진 값을 알려주는 메시지를 response해준다.
  3. 유효성 검사가 끝난 값을 Service로 넘겨준다.

store Service

const rm = require('../../module/util/responseMessage');
const utils = require('../../module/util/utils');
const sc = require('../../module/util/statusCode');
const { sequelize, Store } = require('../../models');

module.exports = {
  readAll: ({
    latitude,
    longitude,
    radius,
  }) => {
    return new Promise(async (resolve, reject) => {
      let store;
      const result = [];
            // [1]
      const long = parseFloat(longitude);
      const lati = parseFloat(latitude);
      try {
                // [2]
        await Store.findAll({
          attributes: ['id', 'name',
            **[
              sequelize.fn('ST_Distance',
                sequelize.fn('POINT', sequelize.col('latitude'),
                  sequelize.col('longitude')), sequelize.fn('POINT', long, lati)),
              'distance'
            ],**
          ],
        })
                // [3]
         .then(async (store) => {
           for (let i = 0; i < store.length; i++) {
             **if(store[i].dataValues.distance <= radius)
               result.push(store[i]);**
           }
         })
      } catch (error) {
        console.log(error.message);
        reject({
          json: utils.successFalse(sc.INTERNAL_SERVER_ERROR, error.message)
        });
      }
      resolve({
        json: utils.successTrue(sc.SUCCESS, "반경 내 매장 조회 성공", result)
      });
    });
  },
}
  1. 받아온 longitude, latitude는 String 이므로 float 형태로 변경해준다.

  2. seqeulize 문법을 많이 사용했다.

    • fn : sequelize 함수를 사용한다.

    • ST_Distance : 두 점 사이의 거리를 계산한다.

    • POINT : 데이터베이스 내에 저장되어 있는 longitude, latitude의 좌표를 리턴한다.

      sequelize.fn('POINT', sequelize.col('latitude'), sequelize.col('longitude'))

    • POINT : request에서 넘어온 longitude, latitude의 좌표를 리턴한다.

      sequelize.fn('POINT', long, lati))

    • [sequelize.fn(...), 'distance'] : Query 문의 AS와 같다.(별칭)

  3. 유효성 검사가 끝난 값을 Service로 넘겨준다.

    • 거리(distance)가 radius보다 작은 row만 result에 push해준다.

테스트

  • POSTMAN으로 테스트를 진행했다.

Response Message

{
    "status": 200,
    "message": "반경 내 매장 조회 성공",
    "data": [
        {
            "id": 1,
            "name": "스위티두 영통점",
            "distance": 114.7061241748854
        },
        {
            "id": 8,
            "name": "보니또 부천원종점",
            "distance": 41.71054908928915
        },
        {
            "id": 11,
            "name": "HOLLEYSCOFFEE 경희대점",
            "distance": 114.70465038076172
        },
        {
            "id": 12,
            "name": "커피나무",
            "distance": 114.7030208193709
        }
    ],
    "success": true
}


마무리

1. 데이터 플로우

  • Router : Client가 접근하는 곳
  • Controller : Router에 들어온 Client의 Request를 보내는 곳, Request의 값들의 유효성 검사
  • Service : Controller에서의 값을 처리하기 위해 보내는 곳, 기능을 담당하는 곳
  • Model : Database 내 명령을 처리를 담당하는 곳

ClientRouterControllerService, Model


2. Sequelize

  • ST_DistancePOINT를 사용하여 두 위도, 경도의 거리 계산이 가능하다.

'Node.js' 카테고리의 다른 글

[Node.js] Sequelize [1]  (0) 2020.01.11
[Node.js] Express  (0) 2020.01.10
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
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
글 보관함