From fdaf99ce41b00e2b3e19d309915199721329808d Mon Sep 17 00:00:00 2001 From: moonyaeyoon Date: Mon, 14 Aug 2023 20:04:34 +0900 Subject: [PATCH 1/8] =?UTF-8?q?=20[MOD]=20:=20=ED=95=80=20=ED=81=B4?= =?UTF-8?q?=EB=A6=AD=ED=96=88=EC=9D=84=20=EB=95=8C=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 17 ++ config/database.js | 16 +- config/pushConnect.js | 12 +- index.js | 4 +- src/app/PinView/pinViewDao.js | 287 +++++++++++++++----------------- src/app/datamap/dmController.js | 41 +++-- src/app/datamap/dmProvider.js | 133 ++++++++------- src/app/datamap/dmRoute.js | 15 +- src/app/datamap/dmService.js | 65 +++++++- src/app/datamap/dmdao.js | 170 +++++++++++-------- 10 files changed, 436 insertions(+), 324 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..1b1aa82 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // IntelliSense를 사용하여 가능한 특성에 대해 알아보세요. + // 기존 특성에 대한 설명을 보려면 가리킵니다. + // 자세한 내용을 보려면 https://go.microsoft.com/fwlink/?linkid=830387을(를) 방문하세요. + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "프로그램 시작", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/index.js" + } + ] +} \ No newline at end of file diff --git a/config/database.js b/config/database.js index 690f8a1..2648ac3 100644 --- a/config/database.js +++ b/config/database.js @@ -1,14 +1,14 @@ -const mysql = require('mysql2/promise'); +const mysql = require("mysql2/promise"); // 본인의 DB 계정 입력 const pool = mysql.createPool({ - host: '', - user: '', - port: '', - password: '', - database: '' + host: "localhost", + user: "moonyaeyoon", + port: "3306", + password: "yaeyoon1004!", + database: "citydata", }); module.exports = { - pool: pool -}; \ No newline at end of file + pool: pool, +}; diff --git a/config/pushConnect.js b/config/pushConnect.js index 3f5879d..13ff641 100644 --- a/config/pushConnect.js +++ b/config/pushConnect.js @@ -1,9 +1,9 @@ -const admin = require("firebase-admin"); +// const admin = require("firebase-admin"); -let serviceAccount = require("../pinple-24129-firebase-adminsdk-kyntj-da88679fe6.json"); +// // let serviceAccount = require("../pinple-24129-firebase-adminsdk-kyntj-da88679fe6.json"); -admin.initializeApp({ - credential: admin.credential.cert(serviceAccount), -}); +// admin.initializeApp({ +// credential: admin.credential.cert(serviceAccount), +// }); -module.exports = admin; +// module.exports = admin; diff --git a/index.js b/index.js index 79f696a..14afd6d 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ -const cors = require('cors'); +const cors = require("cors"); const express = require("./config/express"); const port = 4000; express().listen(port); -console.log(`${process.env.NODE_ENV} - API Server Start At Port ${port}`); \ No newline at end of file +console.log(`${process.env.NODE_ENV} - API Server Start At Port ${port}`); diff --git a/src/app/PinView/pinViewDao.js b/src/app/PinView/pinViewDao.js index 657d284..9969dab 100644 --- a/src/app/PinView/pinViewDao.js +++ b/src/app/PinView/pinViewDao.js @@ -1,22 +1,19 @@ - //핀지도 생성 - async function insertPin(connection, insertPinParams) { - const insertPinQuery = ` +//핀지도 생성 +async function insertPin(connection, insertPinParams) { + const insertPinQuery = ` INSERT INTO pinView(userId, longitude, latitude, address, pinCongest, pinFeeling, contents) VALUES (?, ?, ?, ?, ?, ?, ?); `; - const insertPinRows = await connection.query( - insertPinQuery, - insertPinParams - ); - - return insertPinRows; - } - - //공공 데이터 장소와 핀지도 거리계산(인근 핀 생성) - // -> 핀지도에 넣을지 공공데이터에 넣을지 고민중입니다! - // -> 거리계산값이 정확한지 확인중입니다! - async function insertNearByPin(connection, pinId) { - const insertNearByPinQuery = ` + const insertPinRows = await connection.query(insertPinQuery, insertPinParams); + + return insertPinRows; +} + +//공공 데이터 장소와 핀지도 거리계산(인근 핀 생성) +// -> 핀지도에 넣을지 공공데이터에 넣을지 고민중입니다! +// -> 거리계산값이 정확한지 확인중입니다! +async function insertNearByPin(connection, pinId) { + const insertNearByPinQuery = ` INSERT into nearByPin(pinId, placeId, pinCongest) SELECT p.pinId, c.placeId, p.pinCongest FROM cityData c, pinView p @@ -24,29 +21,28 @@ -radians(p.longitude))+sin(radians(p.latitude))*sin(radians(c.lat)))) < 1), AND pinId = (SELECT MAX(pinId) from pinView); `; - const insertNearByPinRows = await connection.query( - insertNearByPinQuery, - pinId - ); - - return insertNearByPinRows; - } - - //전체 핀지도 조회 - async function selectPin(connection) { - const selectPinListQuery = ` + const insertNearByPinRows = await connection.query( + insertNearByPinQuery, + pinId + ); + + return insertNearByPinRows; +} + +//전체 핀지도 조회 +async function selectPin(connection) { + const selectPinListQuery = ` SELECT pinFeeling, address FROM pinView WHERE status = 1; `; - const [pinRows] = await connection.query(selectPinListQuery); - return pinRows; - } - + const [pinRows] = await connection.query(selectPinListQuery); + return pinRows; +} - //특정 핀지도 조회 - async function selectPinById(connection, pinId, userId) { - const selectPinIdQuery = ` +//특정 핀지도 조회 +async function selectPinById(connection, pinId, userId) { + const selectPinIdQuery = ` SELECT p.address, u.nickname, p.createdAt, p.pinCongest, p.pinFeeling, p.contents, p.likeCount, TIMEDIFF (NOW(), p.createdAt) as passedTime, (SELECT exists ( SELECT userId @@ -56,155 +52,148 @@ FROM pinView p, User u WHERE p.userId = u.userId AND pinId = ${pinId}; `; - const [pinRow] = await connection.query(selectPinIdQuery, pinId, userId); - return pinRow; + const [pinRow] = await connection.query(selectPinIdQuery, pinId, userId); + return pinRow; } - // 최근 조회한 핀지도가 테이블에 이미 있는 경우 삭제 - async function deleteRecentPin(connection, pinId, userId) { - const deleteRecentPinQuery = ` +// 최근 조회한 핀지도가 테이블에 이미 있는 경우 삭제 +async function deleteRecentPin(connection, pinId, userId) { + const deleteRecentPinQuery = ` DELETE FROM pinHistory WHERE pinId = ${pinId} AND userId = ${userId}; `; - const deleteRecentPinRows = await connection.query( - deleteRecentPinQuery, - pinId, - userId - ); - - return deleteRecentPinRows; - } - - //최근 조회한 핀지도 저장 - async function insertRecentPin(connection, pinId, userId) { - const insertRecentPinQuery = ` + const deleteRecentPinRows = await connection.query( + deleteRecentPinQuery, + pinId, + userId + ); + + return deleteRecentPinRows; +} + +//최근 조회한 핀지도 저장 +async function insertRecentPin(connection, pinId, userId) { + const insertRecentPinQuery = ` INSERT INTO pinHistory(pinId, userId) VALUES (${pinId}, ${userId}); `; - const insertRecentPinRows = await connection.query( - insertRecentPinQuery, - pinId, - userId - ); - - return insertRecentPinRows; - } - - //최근 조회한 핀지도 10개 조회 - async function selectRecentPin(connection, userId) { - const selectRecentPinQuery = ` + const insertRecentPinRows = await connection.query( + insertRecentPinQuery, + pinId, + userId + ); + + return insertRecentPinRows; +} + +//최근 조회한 핀지도 10개 조회 +async function selectRecentPin(connection, userId) { + const selectRecentPinQuery = ` SELECT p.pinId, p.pinFeeling, p.address, (TIMEDIFF (NOW(), p.createdAt)) as passedTime FROM pinHistory h, pinView p WHERE h.pinId = p.pinId AND h.userId = ${userId} LIMIT 10; `; - const [selectRecentPinRows] = await connection.query( - selectRecentPinQuery, - userId - ); - - return selectRecentPinRows; - } - - //최근 조회한 핀지도 삭제 - async function deleteMyPin(connection, userId, pinId) { - const deleteMyPinQuery = ` + const [selectRecentPinRows] = await connection.query( + selectRecentPinQuery, + userId + ); + + return selectRecentPinRows; +} + +//최근 조회한 핀지도 삭제 +async function deleteMyPin(connection, userId, pinId) { + const deleteMyPinQuery = ` DELETE FROM pinHistory WHERE userId = ${userId} AND pinId = ${pinId}; `; - const deleteMyPinRows = await connection.query(deleteMyPinQuery, userId, pinId); - return deleteMyPinRows; - } - + const deleteMyPinRows = await connection.query( + deleteMyPinQuery, + userId, + pinId + ); + return deleteMyPinRows; +} - //특정 핀지도 삭제 - async function deletePin(connection, pinId) { - const deletePinQuery = ` +//특정 핀지도 삭제 +async function deletePin(connection, pinId) { + const deletePinQuery = ` UPDATE pinView SET status = 0 WHERE pinId = ?; `; - const deletePinRows = await connection.query(deletePinQuery, pinId); - return deletePinRows; - } - - - //도움이 되었어요 - likeCount 증가 - async function updatePinLikeCount1(connection, pinId) { - const updatePinLikeCountQuery = ` + const deletePinRows = await connection.query(deletePinQuery, pinId); + return deletePinRows; +} + +//도움이 되었어요 - likeCount 증가 +async function updatePinLikeCount1(connection, pinId) { + const updatePinLikeCountQuery = ` UPDATE pinView SET likeCount = likeCount + 1 WHERE pinId = ?; `; - const updatePinLikeCountRows = await connection.query( - updatePinLikeCountQuery, - pinId - ); - return updatePinLikeCountRows; - } - + const updatePinLikeCountRows = await connection.query( + updatePinLikeCountQuery, + pinId + ); + return updatePinLikeCountRows; +} - //도움이 되었어요 - user 추가 - async function insertPinLikeUser(connection, pinId, userId) { - const insertPinLikeQuery = ` +//도움이 되었어요 - user 추가 +async function insertPinLikeUser(connection, pinId, userId) { + const insertPinLikeQuery = ` INSERT INTO likes (pinId, userId) VALUES (${pinId}, ${userId}); `; - const insertPinLikeUserRows = await connection.query( - insertPinLikeQuery, - pinId, - userId - ); - return insertPinLikeUserRows; - } - - - //도움이 되었어요 취소 - likeCount 감소 - async function updatePinLikeCount2(connection, pinId) { - const updatePinLikeCountQuery = ` + const insertPinLikeUserRows = await connection.query( + insertPinLikeQuery, + pinId, + userId + ); + return insertPinLikeUserRows; +} + +//도움이 되었어요 취소 - likeCount 감소 +async function updatePinLikeCount2(connection, pinId) { + const updatePinLikeCountQuery = ` UPDATE pinView SET likeCount = likeCount - 1 WHERE pinId = ?; `; - const updatePinLikeCountRows = await connection.query( - updatePinLikeCountQuery, - pinId - ); - return updatePinLikeCountRows; - } - + const updatePinLikeCountRows = await connection.query( + updatePinLikeCountQuery, + pinId + ); + return updatePinLikeCountRows; +} - //도움이 되었어요 취소 - 유저 삭제 - async function deletePinLikeUser(connection, pinId, userId) { - const deletePinLikeUserQuery = ` +//도움이 되었어요 취소 - 유저 삭제 +async function deletePinLikeUser(connection, pinId, userId) { + const deletePinLikeUserQuery = ` DELETE FROM likes WHERE pinId = ${pinId} AND userId = ${userId}; `; - const deletePinLikeUserRows = await connection.query( - deletePinLikeUserQuery, - pinId, - userId - ); - return deletePinLikeUserRows; - } - - - - - - - module.exports = { - insertPin, - selectPin, - selectPinById, - deleteRecentPin, - insertRecentPin, - selectRecentPin, - deleteMyPin, - deletePin, - updatePinLikeCount1, - updatePinLikeCount2, - insertPinLikeUser, - deletePinLikeUser - - }; \ No newline at end of file + const deletePinLikeUserRows = await connection.query( + deletePinLikeUserQuery, + pinId, + userId + ); + return deletePinLikeUserRows; +} + +module.exports = { + insertPin, + selectPin, + selectPinById, + deleteRecentPin, + insertRecentPin, + selectRecentPin, + deleteMyPin, + deletePin, + updatePinLikeCount1, + updatePinLikeCount2, + insertPinLikeUser, + deletePinLikeUser, +}; diff --git a/src/app/datamap/dmController.js b/src/app/datamap/dmController.js index a5db030..8661129 100644 --- a/src/app/datamap/dmController.js +++ b/src/app/datamap/dmController.js @@ -4,6 +4,7 @@ const axios = require("axios"); const convert = require("xml-js"); const dmProvider = require("./dmProvider"); const dmDao = require("./dmDao"); +const dmService = require("./dmService"); const { pool } = require("../../../config/database"); const urls = { @@ -79,12 +80,12 @@ async function getCategoryData(category) { const xmlData = response.data; const jsonData = convert.xml2json(xmlData, { compact: true, spaces: 4 }); const citydata = JSON.parse(jsonData); - // cityData가 undefined인 경우 빈 객체로 초기화 const cityData = citydata["SeoulRtd.citydata"]["CITYDATA"]; // cityData가 undefined인 경우 빈 객체로 초기화 return { + CODE: code, CATEGORY: category, AREA_NM: cityData ? cityData["AREA_NM"]["_text"] : "", AREA_CONGEST_LVL: cityData @@ -115,7 +116,6 @@ async function getCategoryData(category) { * Name: 장소 혼잡도 API (전체) * [GET] /app/citydata */ - exports.getAllCityData = async function (req, res) { try { const allCategoryData = {}; @@ -125,7 +125,6 @@ exports.getAllCityData = async function (req, res) { }); await Promise.all(categoryPromises); - console.log("all city data :", allCategoryData); // 콘솔에 출력 //citydata 테이블에 도시정보 업데이트 @@ -140,24 +139,42 @@ exports.getAllCityData = async function (req, res) { return res.send(errResponse(responseStatus.SERVER_ERROR)); } }; - /** * API No. 2 - * Name: 상세보기_혼잡도전망 API - * [GET] /app/citydata/details/fcst + * Name: 지도에서 마커 클릭 조회 API + * [GET] /app/pinclick/:code */ -exports.getFcstData = async function (req, res) { + +exports.pinclickByCode = async function (req, res) { + const placeCode = req.params.code; // URL 파라미터에서 이름 가져오기 try { - const fcstData = await dmProvider.getFcstData(); - console.log("Forecast Data:", fcstData); + const placeData = await dmService.createclickPin(placeCode); + console.log("Place Data:", placeData); // 결과값 콘솔에 출력 - return res.send(response(responseStatus.SUCCESS, fcstData)); + return res.send(response(responseStatus.SUCCESS, placeData)); } catch (error) { console.error("Error:", error); return res.send(errResponse(responseStatus.SERVER_ERROR)); } }; +/** + * API No. 3 + * Name: 장소 스크랩 (클릭한 장소) + * [GET] /app/pinclick/:code/scrap + */ + +/** + * API No. 2 + * Name: 상세보기_혼잡도전망 API + * [GET] /app/citydata/details/fcst + */ +exports.getFcstData = async function (req, res) { + console.log("실행되긴하니?"); + const FcstData = await dmProvider.selectFcstData(); + return res.send(response(baseResponse.SUCCESS, FcstData)); +}; + /** * API No. 3 * Name: 상세보기_인근핀 API @@ -182,6 +199,7 @@ exports.getCityDataByCategory = async function (req, res) { randomLocations.map(async (data) => { const values = [ data.CATEGORY, + data.CODE, data.AREA_NM, data.AREA_CONGEST_LVL, data.AREA_CONGEST_MSG, @@ -216,8 +234,7 @@ function shuffleArray(array) { exports.getCityDataSorted = async function (req, res) { try { const sortBy = req.query.sortby; - const cityData = await dmDao.selectCityData(); - const sortedData = await dmProvider.sortDataByCongestion(cityData, sortBy); + const sortedData = await dmProvider.sortDataByCongestion(sortBy); console.log(`Sorted Data (Sort By: ${sortBy}):`, sortedData); return res.send(response(responseStatus.SUCCESS, sortedData)); diff --git a/src/app/datamap/dmProvider.js b/src/app/datamap/dmProvider.js index e3d992a..5cf5c11 100644 --- a/src/app/datamap/dmProvider.js +++ b/src/app/datamap/dmProvider.js @@ -2,82 +2,79 @@ const { pool } = require("../../../config/database"); const dmDao = require("./dmDao"); // citydata 테이블의 모든 데이터를 삭제하고 새로운 데이터를 추가하는 함수 -async function updateAllCityData(cityData) { - try { - await dmDao.deleteAllCityData(); - await dmDao.updateCityData(cityData); - } catch (error) { - throw error; - } +async function updateAllCityData(categoryData) { + try { + const connection = await pool.getConnection(async (conn) => conn); + await dmDao.deleteAllCityData(connection); + const updatedata = await dmDao.updateCityData(connection, categoryData); + connection.release(); + return updatedata; + } catch (error) { + throw error; + } } // 혼잡도 레벨에 따라 우선순위를 반환하는 함수 function getCongestLevelPriority(congestLvl) { - switch (congestLvl) { - case '붐빔': - return 4; - case '약간 붐빔': - return 3; - case '보통': - return 2; - case '여유' : - return 1; - default: - return 0; - } + switch (congestLvl) { + case "붐빔": + return 4; + case "약간 붐빔": + return 3; + case "보통": + return 2; + case "여유": + return 1; + default: + return 0; + } } // 혼잡도에 따라 데이터를 정렬하는 함수 -function sortDataByCongestion(dataArray, sortBy) { - switch (sortBy) { - case "congestion_high": // 혼잡도 높은 순으로 정렬 - dataArray.sort((a, b) => { - const aCongestLvl = getCongestLevelPriority(a.AREA_CONGEST_LVL); - const bCongestLvl = getCongestLevelPriority(b.AREA_CONGEST_LVL); - return bCongestLvl - aCongestLvl; - }); - break; - case "congestion_low": // 혼잡도 낮은 순으로 정렬 - dataArray.sort((a, b) => { - const aCongestLvl = getCongestLevelPriority(a.AREA_CONGEST_LVL); - const bCongestLvl = getCongestLevelPriority(b.AREA_CONGEST_LVL); - return aCongestLvl - bCongestLvl; - }); - break; - case "area_name": // 지역명 가나다 순으로 정렬 - dataArray.sort((a, b) => { - return a.AREA_NM.localeCompare(b.AREA_NM); - }); - break; - default: - // 기본은 혼잡도 높은 순으로 정렬 - dataArray.sort((a, b) => { - const aCongestLvl = getCongestLevelPriority(a.AREA_CONGEST_LVL); - const bCongestLvl = getCongestLevelPriority(b.AREA_CONGEST_LVL); - return bCongestLvl - aCongestLvl; - }); - } - return dataArray; -} -//장소 목록 업데이트 -async function updatePlaceList(dataArray) { - try { - await dmDao.insertPlaceListData(dataArray); - } catch (error) { - throw error; - } -} -//혼잡도전망 데이터를 반환하는 함수 -async function getFcstData() { - try { - const fcstData = await dmDao.selectFcstData(); - return fcstData; - } catch (error) { - throw error; - } +async function sortDataByCongestion(sortBy) { + const dataArray = await dmDao.selectCityData(); + switch (sortBy) { + case "congestion_high": // 혼잡도 높은 순으로 정렬 + dataArray.sort((a, b) => { + const aCongestLvl = getCongestLevelPriority(a.AREA_CONGEST_LVL); + const bCongestLvl = getCongestLevelPriority(b.AREA_CONGEST_LVL); + return bCongestLvl - aCongestLvl; + }); + break; + case "congestion_low": // 혼잡도 낮은 순으로 정렬 + dataArray.sort((a, b) => { + const aCongestLvl = getCongestLevelPriority(a.AREA_CONGEST_LVL); + const bCongestLvl = getCongestLevelPriority(b.AREA_CONGEST_LVL); + return aCongestLvl - bCongestLvl; + }); + break; + case "area_name": // 지역명 가나다 순으로 정렬 + dataArray.sort((a, b) => { + return a.AREA_NM.localeCompare(b.AREA_NM); + }); + break; + default: + // 기본은 혼잡도 높은 순으로 정렬 + dataArray.sort((a, b) => { + const aCongestLvl = getCongestLevelPriority(a.AREA_CONGEST_LVL); + const bCongestLvl = getCongestLevelPriority(b.AREA_CONGEST_LVL); + return bCongestLvl - aCongestLvl; + }); + } + // 정렬된 데이터를 PlaceList 테이블에 삽입 + await dmDao.insertPlaceListData(dataArray); + return dataArray; } +//혼잡도전망 데이터를 반환하는 함수 +async function selectFcstData() { + const connection = await pool.getConnection(async (conn) => conn); + const fcstData = await dmDao.insertFcstData(connection); + connection.release(); + return fcstData; +} module.exports = { - updateAllCityData, sortDataByCongestion, getFcstData, updatePlaceList + updateAllCityData, + sortDataByCongestion, + selectFcstData, }; - diff --git a/src/app/datamap/dmRoute.js b/src/app/datamap/dmRoute.js index 2b23afa..5b6ca6a 100644 --- a/src/app/datamap/dmRoute.js +++ b/src/app/datamap/dmRoute.js @@ -1,9 +1,10 @@ module.exports = function (app) { - const datamap = require('./dmController'); + const datamap = require("./dmController"); - // 공공데이터 API - app.get('/app/citydata', datamap.getAllCityData); - app.get('/app/citydata/details/:category', datamap.getCityDataByCategory); - app.get('/app/citydata/details/fcst',datamap.getFcstData); - app.get('/app/citydata/list', datamap.getCityDataSorted); -} \ No newline at end of file + // 공공데이터 API + app.get("/app/citydata", datamap.getAllCityData); + app.get("/app/pinclick/:code", datamap.pinclickByCode); + app.get("/app/citydata/details/:category", datamap.getCityDataByCategory); + app.get("/app/citydata/details/fcst", datamap.getFcstData); + app.get("/app/citydata/list", datamap.getCityDataSorted); +}; diff --git a/src/app/datamap/dmService.js b/src/app/datamap/dmService.js index 2d26bc2..1c81fbc 100644 --- a/src/app/datamap/dmService.js +++ b/src/app/datamap/dmService.js @@ -1,7 +1,64 @@ -const { pool } = require("../../../config/database"); -const dmDao = require("./dmDao"); +const responseStatus = require("../../../config/responseStatus"); +const { response, errResponse } = require("../../../config/response"); +const axios = require("axios"); +const convert = require("xml-js"); const dmProvider = require("./dmProvider"); -const baseResponse = require("../../../config/responseStatus"); -const {response, errResponse} = require("../../../config/response"); +const dmDao = require("./dmDao"); +const dmController = require("./dmController"); +const { pool } = require("../../../config/database"); + +//마커 클릭했을 때, 해당 장소 데이터 불러오기 +async function createclickPin(placeCode) { + try { + const connection = await pool.getConnection(async (conn) => conn); + //클릭한 장소 정보 불러오기 + const placeData = await dmDao.selectPinDataByCode(connection, placeCode); + //클릭한 장소 스크랩 + + connection.release(); + return placeData; + } catch (error) { + throw error; + } +} + +/* + * 장소 스크랩 + */ +async function createScrap(placeCode) { + const connection = await pool.getConnection(); + try { + // 스크랩 가능한 장소 개수 확인 (최대 3개) + const canScrap = await dmDao.checkScrapLimit(connection); + // 최대 스크랩 개수 초과인 경우 스크랩 불가능 + if (!canScrap) { + connection.release(); + return false; + } + + // 이미 스크랩한 장소인지 확인 + const isAlreadyScrapped = await dmDao.checkIfAlreadyScrapped( + connection, + placeCode + ); + // 이미 스크랩한 장소인 경우 스크랩 불가능 + if (isAlreadyScrapped) { + connection.release(); + return false; + } + + //스크랩 가능한 경우, 장소를 스크랩 테이블에 추가 + await dmDao.insertScrappedPlace(connection, placeCode); + connection.release(); + return true; // 장소 스크랩 성공 + } catch (error) { + connection.release(); + throw error; + } +} +module.exports = { + createclickPin, + createScrap, +}; diff --git a/src/app/datamap/dmdao.js b/src/app/datamap/dmdao.js index 2657699..c7d36da 100644 --- a/src/app/datamap/dmdao.js +++ b/src/app/datamap/dmdao.js @@ -2,25 +2,26 @@ const axios = require("axios"); const convert = require("xml-js"); const { pool } = require("../../../config/database"); -//전체 도시데이터 삽입 -async function insertCityData(extractedDataArray) { +// 공공데이터 불러오기 +async function updateCityData(connection, extractedDataArray) { try { // 쿼리문 작성 const insertcitydataquery = ` - INSERT INTO citydata (CATEGORY, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG, AREA_DATA_TIME, FCST_PPLTN) - VALUES (?, ?, ?, ?, ?, ?) + INSERT INTO citydata (CATEGORY,CODE, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG, AREA_DATA_TIME, FCST_PPLTN) + VALUES (?, ?, ?, ?, ?, ?, ?) `; // 모든 데이터를 Promise.all로 처리하여 데이터베이스에 저장 const savePromises = extractedDataArray.map(async (data) => { const values = [ data.CATEGORY, + data.CODE, data.AREA_NM, data.AREA_CONGEST_LVL, data.AREA_CONGEST_MSG, data.AREA_DATA_TIME, JSON.stringify(data.FCST_PPLTN), ]; - return pool.query(insertcitydataquery, values); + return connection.query(insertcitydataquery, values); }); // 모든 저장 프로미스를 병렬로 실행 @@ -33,6 +34,14 @@ async function insertCityData(extractedDataArray) { throw error; } } + +// citydata테이블 데이터 삭제 (업데이트 위해) +async function deleteAllCityData(connection) { + const delectecityDataquery = "DELETE FROM citydata"; + const deletecitydatarows = await connection.query(delectecityDataquery); + return deletecitydatarows; +} + //전체 도시데이터 조회 async function selectCityData() { try { @@ -43,40 +52,61 @@ async function selectCityData() { throw error; } } -// citydata 테이블에 있는 모든 데이터 삭제 -async function deleteAllCityData() { - try { - const query = "DELETE FROM citydata"; - await pool.query(query); - } catch (error) { - throw error; - } -} -// citydata 테이블에 데이터를 업데이트하는 함수 -async function updateCityData(dataArray) { - try { - const insertCityDataQuery = ` - INSERT INTO citydata (CATEGORY, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG, AREA_DATA_TIME, FCST_PPLTN) - VALUES (?, ?, ?, ?, ?, ?) +//클릭한 마커의 장소 데이터만 불러오기 (by code) +async function selectPinDataByCode(connection, placeCode) { + const selectpinquery = ` + SELECT CODE, CATEGORY, AREA_NM, AREA_CONGEST_LVL + FROM citydata + WHERE CODE = ? `; - const savePromises = dataArray.map(async (data) => { - const values = [ - data.CATEGORY, - data.AREA_NM, - data.AREA_CONGEST_LVL, - data.AREA_CONGEST_MSG, - data.AREA_DATA_TIME, - JSON.stringify(data.FCST_PPLTN), - ]; - return pool.query(insertCityDataQuery, values); - }); + const [selectpinrows] = await connection.query(selectpinquery, [placeCode]); + return selectpinrows; +} - await Promise.all(savePromises); - return true; - } catch (error) { - throw error; - } +/* + * 장소 스크랩 + */ +//스크랩 가능한 장소 개수 확인 (최대 3개) +async function checkScrapLimit(connection) { + const selectScrapCountQuery = ` + SELECT COUNT(*) AS count + FROM scrapPlace + `; + const [selectScrapCountrows] = await connection.query(selectScrapCountQuery); + const currentScrapCount = selectScrapCountrows[0].count; + return currentScrapCount < 3; // 최대 스크랩 가능 개수는 3개 +} + +//이미 스크랩한 장소인지 확인 +async function checkIfAlreadyScrapped(connection, placeCode) { + const selectScrapQuery = ` + SELECT * FROM scrapPlace + WHERE CODE = ? + `; + const [selectScraprows] = await connection.query(selectScrapQuery, [ + placeCode, + ]); + return selectScraprows.length > 0; +} + +//장소 스크랩 추가 +async function insertScrappedPlace(connection, placeCode) { + const insertScrapQuery = ` + INSERT INTO scrapPlace (placeCode) + VALUES (?) + `; + await connection.query(insertScrapQuery, [placeCode]); +} + +// 장소 스크랩 삭제 +async function deleteScrappedPlace(connection, placeCode) { + const deleteScrapQuery = ` + DELETE + FROM scrapPlace + WHERE CODE = ? + `; + await connection.query(deleteScrapQuery, [placeCode]); } // 추천장소 테이블에 데이터를 업데이트하는 함수 @@ -148,8 +178,8 @@ async function selectCityDataByCategory(category) { async function updateRecommendationPlace(dataArray) { try { const insertRecommendationQuery = ` - INSERT INTO recommendationPlace (CATEGORY, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG, AREA_DATA_TIME, FCST_PPLTN) - VALUES (?, ?, ?, ?, ?, ?) + INSERT INTO recommendationPlace (CATEGORY,CODE, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG, AREA_DATA_TIME, FCST_PPLTN) + VALUES (?, ?, ?, ?, ?, ?, ?) `; // 성공적으로 저장된 경우 반환 return pool.query(insertRecommendationQuery, dataArray); @@ -159,35 +189,30 @@ async function updateRecommendationPlace(dataArray) { } } // 데이터를 FcstData 테이블에 삽입하는 함수 -async function insertFcstData(dataArray) { - try { - const insertDataQuery = ` - INSERT INTO FcstData (AREA_NM, FCST_PPLTN) - VALUES (?, ?) - `; - - // dataArray를 map으로 순회하며 각 데이터를 삽입 - const insertPromises = dataArray.map(async (data) => { - const values = [data.AREA_NM, JSON.stringify(data.FCST_PPLTN)]; - - return pool.query(insertDataQuery, values); - }); +async function insertFcstData(connection) { + const selectfcstQuery = ` + SELECT AREA_NM, FCST_PPLTN + FROM citydata + `; + const [fcstRow] = await connection.query(selectfcstQuery); + // FcstData 테이블에 데이터를 삽입 + const insertfcstQuery = ` + INSERT INTO FcstData (AREA_NM, FCST_PPLTN) + VALUES ? + `; - // 모든 삽입 프로미스를 병렬로 실행 - await Promise.all(insertPromises); + const values = fcstRows.map((row) => [row.AREA_NM, row.FCST_PPLTN]); - // 성공적으로 삽입된 경우 반환 - return true; - } catch (error) { - // 삽입 중 오류가 발생한 경우 에러를 던짐 - throw error; - } + await connection.query(insertfcstQuery, [values]); + // 삽입된 데이터 출력 + console.log("Inserted FcstData Row:", fcstRow); + return fcstRow; } // FcstData 테이블에서 데이터를 조회하는 함수 async function selectFcstData() { try { - const query = "SELECT * FROM FcstData"; + const query = "n"; const result = await pool.query(query); return result.rows; } catch (error) { @@ -198,23 +223,27 @@ async function selectFcstData() { // 데이터를 PlaceList 테이블에 삽입하는 함수 async function insertPlaceListData(dataArray) { try { - const insertDataQuery = ` - INSERT INTO PlaceList (CATEGORY,AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG, AREA_DATA_TIME, FCST_PPLTN) - VALUES (?, ?, ?, ?, ?, ?) - `; - + // 모든 삽입 프로미스를 저장할 배열 + const insertPromises = []; // dataArray를 map으로 순회하며 각 데이터를 삽입 - const insertPromises = dataArray.map(async (data) => { + dataArray.forEach((data) => { + const insertDataQuery = ` + INSERT INTO PlaceList (CATEGORY, CODE, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG, AREA_DATA_TIME, FCST_PPLTN) + VALUES (?, ?, ?, ?, ?, ?, ?) + `; const values = [ data.CATEGORY, + data.CODE, data.AREA_NM, data.AREA_CONGEST_LVL, data.AREA_CONGEST_MSG, data.AREA_DATA_TIME, JSON.stringify(data.FCST_PPLTN), ]; + console.log(values); - return pool.query(insertDataQuery, values); + // 각 데이터에 대한 삽입 프로미스를 생성하여 배열에 추가 + insertPromises.push(pool.query(insertDataQuery, values)); }); // 모든 삽입 프로미스를 병렬로 실행 @@ -227,6 +256,7 @@ async function insertPlaceListData(dataArray) { throw error; } } + // PlaceList 테이블에서 데이터를 조회하는 함수 async function selectPlaceListData() { try { @@ -241,8 +271,12 @@ async function selectPlaceListData() { module.exports = { deleteAllCityData, updateCityData, - insertCityData, selectCityData, + selectPinDataByCode, + checkScrapLimit, + checkIfAlreadyScrapped, + insertScrappedPlace, + deleteScrappedPlace, selectCityDataByCategory, updateRecommendationPlace, insertFcstData, From fc2f23938b68a5c86ca3654d88489b605745a87c Mon Sep 17 00:00:00 2001 From: moonyaeyoon Date: Mon, 14 Aug 2023 20:06:14 +0900 Subject: [PATCH 2/8] =?UTF-8?q?=20[MOD]=20:=20=ED=95=80=20=ED=81=B4?= =?UTF-8?q?=EB=A6=AD=ED=96=88=EC=9D=84=20=EB=95=8C=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/datamap/dmService.js | 33 ----------------------------- src/app/datamap/dmdao.js | 40 ------------------------------------ 2 files changed, 73 deletions(-) diff --git a/src/app/datamap/dmService.js b/src/app/datamap/dmService.js index 1c81fbc..d22627a 100644 --- a/src/app/datamap/dmService.js +++ b/src/app/datamap/dmService.js @@ -25,40 +25,7 @@ async function createclickPin(placeCode) { /* * 장소 스크랩 */ -async function createScrap(placeCode) { - const connection = await pool.getConnection(); - try { - // 스크랩 가능한 장소 개수 확인 (최대 3개) - const canScrap = await dmDao.checkScrapLimit(connection); - // 최대 스크랩 개수 초과인 경우 스크랩 불가능 - if (!canScrap) { - connection.release(); - return false; - } - - // 이미 스크랩한 장소인지 확인 - const isAlreadyScrapped = await dmDao.checkIfAlreadyScrapped( - connection, - placeCode - ); - // 이미 스크랩한 장소인 경우 스크랩 불가능 - if (isAlreadyScrapped) { - connection.release(); - return false; - } - - //스크랩 가능한 경우, 장소를 스크랩 테이블에 추가 - await dmDao.insertScrappedPlace(connection, placeCode); - - connection.release(); - return true; // 장소 스크랩 성공 - } catch (error) { - connection.release(); - throw error; - } -} module.exports = { createclickPin, - createScrap, }; diff --git a/src/app/datamap/dmdao.js b/src/app/datamap/dmdao.js index c7d36da..c4bea0d 100644 --- a/src/app/datamap/dmdao.js +++ b/src/app/datamap/dmdao.js @@ -68,46 +68,6 @@ async function selectPinDataByCode(connection, placeCode) { * 장소 스크랩 */ //스크랩 가능한 장소 개수 확인 (최대 3개) -async function checkScrapLimit(connection) { - const selectScrapCountQuery = ` - SELECT COUNT(*) AS count - FROM scrapPlace - `; - const [selectScrapCountrows] = await connection.query(selectScrapCountQuery); - const currentScrapCount = selectScrapCountrows[0].count; - return currentScrapCount < 3; // 최대 스크랩 가능 개수는 3개 -} - -//이미 스크랩한 장소인지 확인 -async function checkIfAlreadyScrapped(connection, placeCode) { - const selectScrapQuery = ` - SELECT * FROM scrapPlace - WHERE CODE = ? - `; - const [selectScraprows] = await connection.query(selectScrapQuery, [ - placeCode, - ]); - return selectScraprows.length > 0; -} - -//장소 스크랩 추가 -async function insertScrappedPlace(connection, placeCode) { - const insertScrapQuery = ` - INSERT INTO scrapPlace (placeCode) - VALUES (?) - `; - await connection.query(insertScrapQuery, [placeCode]); -} - -// 장소 스크랩 삭제 -async function deleteScrappedPlace(connection, placeCode) { - const deleteScrapQuery = ` - DELETE - FROM scrapPlace - WHERE CODE = ? - `; - await connection.query(deleteScrapQuery, [placeCode]); -} // 추천장소 테이블에 데이터를 업데이트하는 함수 async function updateRecommendationPlace(values) { From 43d249439a6f0d78aa84e113e1205b1edbd57a57 Mon Sep 17 00:00:00 2001 From: moonyaeyoon Date: Tue, 15 Aug 2023 12:18:14 +0900 Subject: [PATCH 3/8] =?UTF-8?q?=20[FEAT]=20:=20=EB=A7=88=EC=BB=A4=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=20=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/datamap/dmController.js | 38 +++++++++++++++++++++++++++++ src/app/datamap/dmProvider.js | 9 +++++++ src/app/datamap/dmRoute.js | 10 ++++++++ src/app/datamap/dmService.js | 38 +++++++++++++++++++++++++++++ src/app/datamap/dmdao.js | 43 ++++++++++++++++++++++++++++++--- 5 files changed, 134 insertions(+), 4 deletions(-) diff --git a/src/app/datamap/dmController.js b/src/app/datamap/dmController.js index 8661129..7d0f2be 100644 --- a/src/app/datamap/dmController.js +++ b/src/app/datamap/dmController.js @@ -163,7 +163,45 @@ exports.pinclickByCode = async function (req, res) { * Name: 장소 스크랩 (클릭한 장소) * [GET] /app/pinclick/:code/scrap */ +// 유저 아이디는 JWT 토큰으로 넘겨받고, 데이터 지도에서 스크랩할 place_id를 파라미터로 넘겨주면 scrap db에 저장되는 형식입니다! +/** + * API No. + * Name: 데이터 지도 스크랩 + * [POST] /app/map/:place_id/scrap + */ +exports.postScrap = async function (req, res) { + const userId = req.verifiedToken.userId; // 현재 로그인한 userId + const placeId = req.params.place_id; + console.log(userId, placeId); + const scrapResult = await dmService.createScrap(userId, placeId); + return res.send(response(responseStatus.SUCCESS, scrapResult)); +}; + +/** + * API No. + * Name: 스크랩 조회 + * [GET] /app/myPage/scrap + */ +exports.getScrap = async function (req, res) { + const userId = req.verifiedToken.userId; // 현재 로그인한 userId + const scrapResult = await dmProvider.retrieveScrap(userId); + return res.send(response(responseStatus.SUCCESS, scrapResult)); +}; + +/** + * API No. + * Name: 스크랩 삭제 + * [DELETE] /app/map/:place_id/scrap + */ +exports.deleteScrap = async function (req, res) { + const userId = req.verifiedToken.userId; // 현재 로그인한 userId + const placeId = req.params.place_id; + + // if (!placeId) return res.send(errResponse(baseResponse.SCRAP_PLACEID_EMPTY)); + const deleteScrapResponse = await dmService.deleteScrap(userId, placeId); + return res.send(deleteScrapResponse); +}; /** * API No. 2 * Name: 상세보기_혼잡도전망 API diff --git a/src/app/datamap/dmProvider.js b/src/app/datamap/dmProvider.js index 5cf5c11..32b9958 100644 --- a/src/app/datamap/dmProvider.js +++ b/src/app/datamap/dmProvider.js @@ -72,9 +72,18 @@ async function selectFcstData() { connection.release(); return fcstData; } +//스크랩 +async function retrieveScrap(userId) { + const connection = await pool.getConnection(async (conn) => conn); + const scrapResult = await userDao.selectScraps(connection, userId); + connection.release(); + + return scrapResult; +} module.exports = { updateAllCityData, sortDataByCongestion, selectFcstData, + retrieveScrap, }; diff --git a/src/app/datamap/dmRoute.js b/src/app/datamap/dmRoute.js index 5b6ca6a..0bc4f88 100644 --- a/src/app/datamap/dmRoute.js +++ b/src/app/datamap/dmRoute.js @@ -7,4 +7,14 @@ module.exports = function (app) { app.get("/app/citydata/details/:category", datamap.getCityDataByCategory); app.get("/app/citydata/details/fcst", datamap.getFcstData); app.get("/app/citydata/list", datamap.getCityDataSorted); + // 임의로 라우터 uri를 정한거라 편하신대로 수정하셔도 괜찮습니다! + // 데이터 지도 스크랩 + app.post("/app/map/:place_id/scrap", datamap.postScrap); + + // 스크랩 삭제 + app.delete("/app/map/:place_id/scrap", datamap.deleteScrap); + + // 스크랩 조회의 경우 프론트 단에선 mypage에서 이뤄지는 것 같은데 백에선 같은 데이터 지도 스크랩 파트라 함께 올립니다! + // 스크랩 조회 + app.get("/app/myPage/scrap", datamap.getScrap); }; diff --git a/src/app/datamap/dmService.js b/src/app/datamap/dmService.js index d22627a..941360e 100644 --- a/src/app/datamap/dmService.js +++ b/src/app/datamap/dmService.js @@ -25,7 +25,45 @@ async function createclickPin(placeCode) { /* * 장소 스크랩 */ +async function createScrap(userId, placeId) { + try { + const connection = await pool.getConnection(async (conn) => conn); + const insertScrapParams = [userId, placeId]; + const creatScrapResult = await dmDao.insertScrap( + connection, + insertScrapParams + ); + console.log(`스크랩 : ${creatScrapResult[0]}`); + connection.release(); + return response(baseResponse.SUCCESS); + } catch (err) { + return errResponse(baseResponse.DB_ERROR); + } +} + +async function deleteScrap(userId, placeId) { + try { + // const roleRows = await userProvider.scrapWriterCheck(userId, placeId); + //const writerCheck = roleRows[0].writer_id + // if (writer_id !== writerCheck){ + // return errResponse(baseResponse.QUESTION_AUTH); + // } + const connection = await pool.getConnection(async (conn) => conn); + const deleteScrapParams = [userId, placeId]; + const deleteScrapResult = await dmDao.deleteScrap( + connection, + deleteScrapParams + ); + console.log(deleteScrapResult); + connection.release(); + return response(baseResponse.SUCCESS); + } catch (err) { + return errResponse(baseResponse.DB_ERROR); + } +} module.exports = { createclickPin, + createScrap, + deleteScrap, }; diff --git a/src/app/datamap/dmdao.js b/src/app/datamap/dmdao.js index c4bea0d..42baee6 100644 --- a/src/app/datamap/dmdao.js +++ b/src/app/datamap/dmdao.js @@ -227,16 +227,51 @@ async function selectPlaceListData() { throw error; } } +// erd cloud에 업로드한 table 형태 참고해서 insert하고 select하도록 했습니다! 편하신대로 수정하셔도 괜찮습니다! +async function insertScrap(connection, insertScrapParams) { + const insertQuestionQuery = ` + INSERT INTO scrap(userId, place_id) + VALUES(?, ?); + `; + + const insertScrapRows = await connection.query( + insertQuestionQuery, + insertScrapParams + ); + return insertScrapRows; +} + +// scrap 테이블에 저장된 place_id로 db에 저장된 citydata를 조회하도록 했습니다! +async function selectScraps(connection, userId) { + const selectScrapsQuery = ` + SELECT c.area_nm, c.road_addr, c.area_congest_lvl + FROM citydata c JOIN scrap s ON c.place_id = s.place_id + where s.userId = ?; + `; + const [questionRow] = await connection.query(selectScrapsQuery, userId); + return questionRow; +} + +async function deleteScrap(connection, deleteScrapParams) { + const deleteQuestionQuery = ` + DELETE FROM scrap + WHERE userId = ? AND place_id =?; + `; + const deleteQuestionRows = await connection.query( + deleteQuestionQuery, + deleteScrapParams + ); + return deleteQuestionRows; +} module.exports = { deleteAllCityData, updateCityData, selectCityData, selectPinDataByCode, - checkScrapLimit, - checkIfAlreadyScrapped, - insertScrappedPlace, - deleteScrappedPlace, + insertScrap, + selectScraps, + deleteScrap, selectCityDataByCategory, updateRecommendationPlace, insertFcstData, From 8a7b1ccf7a41f2b50f7afb1d07fea55a112da77d Mon Sep 17 00:00:00 2001 From: moonyaeyoon Date: Tue, 15 Aug 2023 16:08:54 +0900 Subject: [PATCH 4/8] =?UTF-8?q?[ADD]:=EC=83=81=EC=84=B8=EB=B3=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/datamap/dmController.js | 93 ++++++--------------- src/app/datamap/dmProvider.js | 26 +++++- src/app/datamap/dmRoute.js | 13 +-- src/app/datamap/dmService.js | 12 +++ src/app/datamap/dmdao.js | 138 +++++++------------------------- 5 files changed, 96 insertions(+), 186 deletions(-) diff --git a/src/app/datamap/dmController.js b/src/app/datamap/dmController.js index 7d0f2be..b380e72 100644 --- a/src/app/datamap/dmController.js +++ b/src/app/datamap/dmController.js @@ -145,7 +145,7 @@ exports.getAllCityData = async function (req, res) { * [GET] /app/pinclick/:code */ -exports.pinclickByCode = async function (req, res) { +exports.getpinclickByCode = async function (req, res) { const placeCode = req.params.code; // URL 파라미터에서 이름 가져오기 try { const placeData = await dmService.createclickPin(placeCode); @@ -157,15 +157,32 @@ exports.pinclickByCode = async function (req, res) { return res.send(errResponse(responseStatus.SERVER_ERROR)); } }; - /** * API No. 3 - * Name: 장소 스크랩 (클릭한 장소) - * [GET] /app/pinclick/:code/scrap + * Name: 상세보기 + * [GET] /app/pinclick/:code/details */ +exports.getDetails = async function (req, res) { + const placeCode = req.params.code; + + try { + const { markerDetails, recommendationPlaces } = + await dmService.createDetails(placeCode); + + console.log("Marker Details:", markerDetails); + console.log("Random Places:", recommendationPlaces); + return res.send( + response(responseStatus.SUCCESS, { markerDetails, recommendationPlaces }) + ); + } catch (error) { + console.error("Error:", error); + return res.send(errResponse(responseStatus.SERVER_ERROR)); + } +}; + // 유저 아이디는 JWT 토큰으로 넘겨받고, 데이터 지도에서 스크랩할 place_id를 파라미터로 넘겨주면 scrap db에 저장되는 형식입니다! /** - * API No. + * API No.4 * Name: 데이터 지도 스크랩 * [POST] /app/map/:place_id/scrap */ @@ -178,7 +195,7 @@ exports.postScrap = async function (req, res) { }; /** - * API No. + * API No.5 * Name: 스크랩 조회 * [GET] /app/myPage/scrap */ @@ -189,7 +206,7 @@ exports.getScrap = async function (req, res) { }; /** - * API No. + * API No.6 * Name: 스크랩 삭제 * [DELETE] /app/map/:place_id/scrap */ @@ -202,69 +219,9 @@ exports.deleteScrap = async function (req, res) { const deleteScrapResponse = await dmService.deleteScrap(userId, placeId); return res.send(deleteScrapResponse); }; -/** - * API No. 2 - * Name: 상세보기_혼잡도전망 API - * [GET] /app/citydata/details/fcst - */ -exports.getFcstData = async function (req, res) { - console.log("실행되긴하니?"); - const FcstData = await dmProvider.selectFcstData(); - return res.send(response(baseResponse.SUCCESS, FcstData)); -}; - -/** - * API No. 3 - * Name: 상세보기_인근핀 API - * [GET] /app/citydata/details/pin - */ /** - * API No. 4 - * Name: 상세보기_추천장소 API - * [GET] /app/citydata/details/:category - */ -exports.getCityDataByCategory = async function (req, res) { - try { - const category = req.params.category; - const categoryData = await getCategoryData(category); - - // Shuffle the categoryData array to get a random order of locations - shuffleArray(categoryData); - - // Get the first 3 locations from the shuffled array - const randomLocations = categoryData.slice(0, 3); - randomLocations.map(async (data) => { - const values = [ - data.CATEGORY, - data.CODE, - data.AREA_NM, - data.AREA_CONGEST_LVL, - data.AREA_CONGEST_MSG, - data.AREA_DATA_TIME, - JSON.stringify(data.FCST_PPLTN), - ]; - await dmDao.updateRecommendationPlace(values); - }); - - console.log(`Category Data for ${category}:`, randomLocations); // Log the randomly selected locations - - return res.send(response(responseStatus.SUCCESS, randomLocations)); - } catch (error) { - console.error("Error:", error); - return res.send(errResponse(responseStatus.SERVER_ERROR)); - } -}; - -// Function to shuffle an array randomly -function shuffleArray(array) { - for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; - } -} -/** - * API No. 5 + * API No. 7 * Name: 장소 목록 API (혼잡도 높은순, 혼잡도 낮은순, 가나다순) * [GET] /app/citydata/list?sortby={} */ diff --git a/src/app/datamap/dmProvider.js b/src/app/datamap/dmProvider.js index 32b9958..5166ee4 100644 --- a/src/app/datamap/dmProvider.js +++ b/src/app/datamap/dmProvider.js @@ -75,15 +75,39 @@ async function selectFcstData() { //스크랩 async function retrieveScrap(userId) { const connection = await pool.getConnection(async (conn) => conn); - const scrapResult = await userDao.selectScraps(connection, userId); + const scrapResult = await dmDao.selectScraps(connection, userId); connection.release(); return scrapResult; } +//상세보기 조회 (장소 정보, 혼잡도 전망, 추천장소) +async function retrieveDetails(placeCode) { + try { + const connection = await pool.getConnection(async (conn) => conn); + + const markerDetails = await dmDao.selectMarkerDetails( + connection, + placeCode + ); + const category = markerDetails[0].CATEGORY; + console.log("마커카테고리", category); + const recommendationPlaces = await dmDao.selectRecommendationPlaces( + connection, + category + ); + connection.release(); + + return { markerDetails, recommendationPlaces }; + } catch (error) { + throw error; + } +} + module.exports = { updateAllCityData, sortDataByCongestion, selectFcstData, retrieveScrap, + retrieveDetails, }; diff --git a/src/app/datamap/dmRoute.js b/src/app/datamap/dmRoute.js index 0bc4f88..2370167 100644 --- a/src/app/datamap/dmRoute.js +++ b/src/app/datamap/dmRoute.js @@ -3,16 +3,17 @@ module.exports = function (app) { // 공공데이터 API app.get("/app/citydata", datamap.getAllCityData); - app.get("/app/pinclick/:code", datamap.pinclickByCode); - app.get("/app/citydata/details/:category", datamap.getCityDataByCategory); - app.get("/app/citydata/details/fcst", datamap.getFcstData); + app.get("/app/pinclick/:code", datamap.getpinclickByCode); + app.get("/app/pinclick/:code/details", datamap.getDetails); + // app.get("/app/citydata/details/:category", datamap.getCityDataByCategory); + // app.get("/app/citydata/details/fcst", datamap.getFcstData); app.get("/app/citydata/list", datamap.getCityDataSorted); // 임의로 라우터 uri를 정한거라 편하신대로 수정하셔도 괜찮습니다! // 데이터 지도 스크랩 - app.post("/app/map/:place_id/scrap", datamap.postScrap); + // app.post("/app/map/:place_id/scrap", datamap.postScrap); - // 스크랩 삭제 - app.delete("/app/map/:place_id/scrap", datamap.deleteScrap); + // // 스크랩 삭제 + // app.delete("/app/map/:place_id/scrap", datamap.deleteScrap); // 스크랩 조회의 경우 프론트 단에선 mypage에서 이뤄지는 것 같은데 백에선 같은 데이터 지도 스크랩 파트라 함께 올립니다! // 스크랩 조회 diff --git a/src/app/datamap/dmService.js b/src/app/datamap/dmService.js index 941360e..72457ae 100644 --- a/src/app/datamap/dmService.js +++ b/src/app/datamap/dmService.js @@ -62,8 +62,20 @@ async function deleteScrap(userId, placeId) { } } +//상세보기 +async function createDetails(placeCode) { + try { + const { markerDetails, recommendationPlaces } = + await dmProvider.retrieveDetails(placeCode); + return { markerDetails, recommendationPlaces }; + } catch (error) { + throw error; + } +} + module.exports = { createclickPin, createScrap, deleteScrap, + createDetails, }; diff --git a/src/app/datamap/dmdao.js b/src/app/datamap/dmdao.js index 42baee6..2b11f08 100644 --- a/src/app/datamap/dmdao.js +++ b/src/app/datamap/dmdao.js @@ -56,7 +56,7 @@ async function selectCityData() { //클릭한 마커의 장소 데이터만 불러오기 (by code) async function selectPinDataByCode(connection, placeCode) { const selectpinquery = ` - SELECT CODE, CATEGORY, AREA_NM, AREA_CONGEST_LVL + SELECT CODE, CATEGORY, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG FROM citydata WHERE CODE = ? `; @@ -69,115 +69,33 @@ async function selectPinDataByCode(connection, placeCode) { */ //스크랩 가능한 장소 개수 확인 (최대 3개) -// 추천장소 테이블에 데이터를 업데이트하는 함수 -async function updateRecommendationPlace(values) { - try { - const insertRecommendationQuery = ` - INSERT INTO recommendationPlace (CATEGORY, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG, AREA_DATA_TIME, FCST_PPLTN) - VALUES (?, ?, ?, ?, ?, ?) - `; - - // const values = [ - // data.CATEGORY, - // data.AREA_NM, - // data.AREA_CONGEST_LVL, - // data.AREA_CONGEST_MSG, - // data.AREA_DATA_TIME, - // JSON.stringify(data.FCST_PPLTN), - // ]; - await pool.query(insertRecommendationQuery, values); - // dataArray.map(async (data) => { - // console.log(data); - // const values = [ - // data.CATEGORY, - // data.AREA_NM, - // data.AREA_CONGEST_LVL, - // data.AREA_CONGEST_MSG, - // data.AREA_DATA_TIME, - // JSON.stringify(data.FCST_PPLTN), - // ]; - // await pool.query(insertRecommendationQuery, values); - // }); - - // const updatePromises = dataArray.map(async (data) => { - // const values = [ - // data.CATEGORY, - // data.AREA_NM, - // data.AREA_CONGEST_LVL, - // data.AREA_CONGEST_MSG, - // data.AREA_DATA_TIME, - // JSON.stringify(data.FCST_PPLTN), - // ]; - // return pool.query(insertRecommendationQuery, values); - // }); - - // await Promise.all(updatePromises); - - // 성공적으로 저장된 경우 반환 - return true; - } catch (error) { - // 저장 중 오류가 발생한 경우 에러를 던짐 - throw error; - } -} - -// citydata 테이블에서 해당 카테고리 데이터를 추출하는 함수 -async function selectCityDataByCategory(category) { - try { - const selectCityDatabyCategoryquery = - "SELECT * FROM citydata WHERE CATEGORY = ?"; - const values = [category]; - const result = await pool.query(selectCityDatabyCategoryquery, values); - return result.rows; - } catch (error) { - throw error; - } -} - -// 추천장소 테이블에 데이터를 업데이트하는 함수 -async function updateRecommendationPlace(dataArray) { - try { - const insertRecommendationQuery = ` - INSERT INTO recommendationPlace (CATEGORY,CODE, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG, AREA_DATA_TIME, FCST_PPLTN) - VALUES (?, ?, ?, ?, ?, ?, ?) - `; - // 성공적으로 저장된 경우 반환 - return pool.query(insertRecommendationQuery, dataArray); - } catch (error) { - // 저장 중 오류가 발생한 경우 에러를 던짐 - throw error; - } -} -// 데이터를 FcstData 테이블에 삽입하는 함수 -async function insertFcstData(connection) { - const selectfcstQuery = ` - SELECT AREA_NM, FCST_PPLTN - FROM citydata +// 상세보기_클릭한 장소 정보 +async function selectMarkerDetails(connection, placeCode) { + const selectMarkerDetailsQuery = ` + SELECT c.CODE, c.CATEGORY, c.AREA_NM, c.AREA_CONGEST_LVL, c.AREA_CONGEST_MSG, c.FCST_PPLTN + FROM citydata c + WHERE c.CODE = ?; `; - const [fcstRow] = await connection.query(selectfcstQuery); - // FcstData 테이블에 데이터를 삽입 - const insertfcstQuery = ` - INSERT INTO FcstData (AREA_NM, FCST_PPLTN) - VALUES ? - `; - - const values = fcstRows.map((row) => [row.AREA_NM, row.FCST_PPLTN]); - - await connection.query(insertfcstQuery, [values]); - // 삽입된 데이터 출력 - console.log("Inserted FcstData Row:", fcstRow); - return fcstRow; + const [markerDetailsRows] = await connection.query(selectMarkerDetailsQuery, [ + placeCode, + ]); + return markerDetailsRows; } -// FcstData 테이블에서 데이터를 조회하는 함수 -async function selectFcstData() { - try { - const query = "n"; - const result = await pool.query(query); - return result.rows; - } catch (error) { - throw error; - } +// 상세보기_클릭한 장소와 동일 카테고리 장소 추천 (3곳) +async function selectRecommendationPlaces(connection, category, limit = 3) { + const selectRecommendationPlacesQuery = ` + SELECT c.CATEGORY, c.AREA_NM, c.AREA_CONGEST_LVL + FROM citydata c + WHERE c.CATEGORY = ? + ORDER BY RAND() + LIMIT ?; + `; + const [recommendationPlacesRows] = await connection.query( + selectRecommendationPlacesQuery, + [category, limit] + ); + return recommendationPlacesRows; } // 데이터를 PlaceList 테이블에 삽입하는 함수 @@ -272,10 +190,8 @@ module.exports = { insertScrap, selectScraps, deleteScrap, - selectCityDataByCategory, - updateRecommendationPlace, - insertFcstData, - selectFcstData, + selectMarkerDetails, + selectRecommendationPlaces, insertPlaceListData, selectPlaceListData, }; From b12b68cf03be94fbdeba06d8d9b42af0ff69b9d5 Mon Sep 17 00:00:00 2001 From: moonyaeyoon Date: Tue, 15 Aug 2023 20:17:08 +0900 Subject: [PATCH 5/8] =?UTF-8?q?[CHORE]=20:=20=EC=8A=A4=ED=81=AC=EB=9E=A9,?= =?UTF-8?q?=20=EC=83=81=EC=84=B8=EB=B3=B4=EA=B8=B0,=20=EB=AA=A9=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/datamap/dmController.js | 15 ++++--- src/app/datamap/dmProvider.js | 68 ++++-------------------------- src/app/datamap/dmRoute.js | 8 ++-- src/app/datamap/dmService.js | 7 ++++ src/app/datamap/dmdao.js | 73 +++++++++++---------------------- 5 files changed, 48 insertions(+), 123 deletions(-) diff --git a/src/app/datamap/dmController.js b/src/app/datamap/dmController.js index b380e72..7e4c716 100644 --- a/src/app/datamap/dmController.js +++ b/src/app/datamap/dmController.js @@ -223,18 +223,17 @@ exports.deleteScrap = async function (req, res) { /** * API No. 7 * Name: 장소 목록 API (혼잡도 높은순, 혼잡도 낮은순, 가나다순) - * [GET] /app/citydata/list?sortby={} + * [GET] /app/list/:sortby */ -exports.getCityDataSorted = async function (req, res) { - try { - const sortBy = req.query.sortby; - const sortedData = await dmProvider.sortDataByCongestion(sortBy); - console.log(`Sorted Data (Sort By: ${sortBy}):`, sortedData); +exports.getCityDataList = async function (req, res) { + const sortBy = req.query.sortby; - return res.send(response(responseStatus.SUCCESS, sortedData)); + try { + const cityDataList = await dmService.createCityList(sortBy); + return res.send(cityDataList); } catch (error) { console.error("Error:", error); - return res.send(errResponse(responseStatus.SERVER_ERROR)); + return res.sendStatus(500); } }; diff --git a/src/app/datamap/dmProvider.js b/src/app/datamap/dmProvider.js index 5166ee4..2d56f72 100644 --- a/src/app/datamap/dmProvider.js +++ b/src/app/datamap/dmProvider.js @@ -13,65 +13,7 @@ async function updateAllCityData(categoryData) { throw error; } } -// 혼잡도 레벨에 따라 우선순위를 반환하는 함수 -function getCongestLevelPriority(congestLvl) { - switch (congestLvl) { - case "붐빔": - return 4; - case "약간 붐빔": - return 3; - case "보통": - return 2; - case "여유": - return 1; - default: - return 0; - } -} - -// 혼잡도에 따라 데이터를 정렬하는 함수 -async function sortDataByCongestion(sortBy) { - const dataArray = await dmDao.selectCityData(); - switch (sortBy) { - case "congestion_high": // 혼잡도 높은 순으로 정렬 - dataArray.sort((a, b) => { - const aCongestLvl = getCongestLevelPriority(a.AREA_CONGEST_LVL); - const bCongestLvl = getCongestLevelPriority(b.AREA_CONGEST_LVL); - return bCongestLvl - aCongestLvl; - }); - break; - case "congestion_low": // 혼잡도 낮은 순으로 정렬 - dataArray.sort((a, b) => { - const aCongestLvl = getCongestLevelPriority(a.AREA_CONGEST_LVL); - const bCongestLvl = getCongestLevelPriority(b.AREA_CONGEST_LVL); - return aCongestLvl - bCongestLvl; - }); - break; - case "area_name": // 지역명 가나다 순으로 정렬 - dataArray.sort((a, b) => { - return a.AREA_NM.localeCompare(b.AREA_NM); - }); - break; - default: - // 기본은 혼잡도 높은 순으로 정렬 - dataArray.sort((a, b) => { - const aCongestLvl = getCongestLevelPriority(a.AREA_CONGEST_LVL); - const bCongestLvl = getCongestLevelPriority(b.AREA_CONGEST_LVL); - return bCongestLvl - aCongestLvl; - }); - } - // 정렬된 데이터를 PlaceList 테이블에 삽입 - await dmDao.insertPlaceListData(dataArray); - return dataArray; -} -//혼잡도전망 데이터를 반환하는 함수 -async function selectFcstData() { - const connection = await pool.getConnection(async (conn) => conn); - const fcstData = await dmDao.insertFcstData(connection); - connection.release(); - return fcstData; -} //스크랩 async function retrieveScrap(userId) { const connection = await pool.getConnection(async (conn) => conn); @@ -103,11 +45,17 @@ async function retrieveDetails(placeCode) { throw error; } } +//장소 목록 +async function retrieveCityList(sortBy) { + const connection = await pool.getConnection(async (conn) => conn); + const cityDataList = await dmDao.selectCityList(connection, sortBy); + connection.release(); + return cityDataList; +} module.exports = { updateAllCityData, - sortDataByCongestion, - selectFcstData, retrieveScrap, retrieveDetails, + retrieveCityList, }; diff --git a/src/app/datamap/dmRoute.js b/src/app/datamap/dmRoute.js index 2370167..5648e7e 100644 --- a/src/app/datamap/dmRoute.js +++ b/src/app/datamap/dmRoute.js @@ -10,11 +10,9 @@ module.exports = function (app) { app.get("/app/citydata/list", datamap.getCityDataSorted); // 임의로 라우터 uri를 정한거라 편하신대로 수정하셔도 괜찮습니다! // 데이터 지도 스크랩 - // app.post("/app/map/:place_id/scrap", datamap.postScrap); - - // // 스크랩 삭제 - // app.delete("/app/map/:place_id/scrap", datamap.deleteScrap); - + app.post("/app/map/:place_id/scrap", datamap.postScrap); + //스크랩 삭제 + app.delete("/app/map/:place_id/scrap", datamap.deleteScrap); // 스크랩 조회의 경우 프론트 단에선 mypage에서 이뤄지는 것 같은데 백에선 같은 데이터 지도 스크랩 파트라 함께 올립니다! // 스크랩 조회 app.get("/app/myPage/scrap", datamap.getScrap); diff --git a/src/app/datamap/dmService.js b/src/app/datamap/dmService.js index 72457ae..4ea84c0 100644 --- a/src/app/datamap/dmService.js +++ b/src/app/datamap/dmService.js @@ -73,9 +73,16 @@ async function createDetails(placeCode) { } } +// 장소 목록 +async function createCityList(sortBy) { + const cityList = await dmProvider.retrieveCityList(sortBy); + return cityList; +} + module.exports = { createclickPin, createScrap, deleteScrap, createDetails, + createCityList, }; diff --git a/src/app/datamap/dmdao.js b/src/app/datamap/dmdao.js index 2b11f08..df5f4cb 100644 --- a/src/app/datamap/dmdao.js +++ b/src/app/datamap/dmdao.js @@ -98,53 +98,6 @@ async function selectRecommendationPlaces(connection, category, limit = 3) { return recommendationPlacesRows; } -// 데이터를 PlaceList 테이블에 삽입하는 함수 -async function insertPlaceListData(dataArray) { - try { - // 모든 삽입 프로미스를 저장할 배열 - const insertPromises = []; - // dataArray를 map으로 순회하며 각 데이터를 삽입 - dataArray.forEach((data) => { - const insertDataQuery = ` - INSERT INTO PlaceList (CATEGORY, CODE, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG, AREA_DATA_TIME, FCST_PPLTN) - VALUES (?, ?, ?, ?, ?, ?, ?) - `; - const values = [ - data.CATEGORY, - data.CODE, - data.AREA_NM, - data.AREA_CONGEST_LVL, - data.AREA_CONGEST_MSG, - data.AREA_DATA_TIME, - JSON.stringify(data.FCST_PPLTN), - ]; - console.log(values); - - // 각 데이터에 대한 삽입 프로미스를 생성하여 배열에 추가 - insertPromises.push(pool.query(insertDataQuery, values)); - }); - - // 모든 삽입 프로미스를 병렬로 실행 - await Promise.all(insertPromises); - - // 성공적으로 삽입된 경우 반환 - return true; - } catch (error) { - // 삽입 중 오류가 발생한 경우 에러를 던짐 - throw error; - } -} - -// PlaceList 테이블에서 데이터를 조회하는 함수 -async function selectPlaceListData() { - try { - const selectDataQuery = "SELECT * FROM PlaceList"; - const result = await pool.query(selectDataQuery); - return result.rows; - } catch (error) { - throw error; - } -} // erd cloud에 업로드한 table 형태 참고해서 insert하고 select하도록 했습니다! 편하신대로 수정하셔도 괜찮습니다! async function insertScrap(connection, insertScrapParams) { const insertQuestionQuery = ` @@ -169,7 +122,7 @@ async function selectScraps(connection, userId) { const [questionRow] = await connection.query(selectScrapsQuery, userId); return questionRow; } - +//스크랩 삭제 async function deleteScrap(connection, deleteScrapParams) { const deleteQuestionQuery = ` DELETE FROM scrap @@ -182,6 +135,27 @@ async function deleteScrap(connection, deleteScrapParams) { return deleteQuestionRows; } +//장소 목록 +async function selectCityList(connection, sortBy) { + let orderByClause = ""; + if (sortBy === "high") { + orderByClause = + 'ORDER BY FIELD(CONGEST_LVL, "붐빔", "약간 붐빔", "보통", "여유")'; + } else if (sortBy === "low") { + orderByClause = + 'ORDER BY FIELD(CONGEST_LVL, "여유", "보통", "약간 붐빔", "붐빔")'; + } else if (sortBy === "name") { + orderByClause = "ORDER BY AREA_NM"; + } + const selectCityListQuery = ` + SELECT AREA_NM, AREA_CONGEST_LVL + FROM citydata + ${orderByClause}; + `; + const [cityListRows] = await connection.query(selectCityListQuery); + return cityListRows; +} + module.exports = { deleteAllCityData, updateCityData, @@ -192,6 +166,5 @@ module.exports = { deleteScrap, selectMarkerDetails, selectRecommendationPlaces, - insertPlaceListData, - selectPlaceListData, + selectCityList, }; From 070d883c1b551d606134b3f27661a0cd3483b361 Mon Sep 17 00:00:00 2001 From: moonyaeyoon Date: Tue, 15 Aug 2023 20:31:39 +0900 Subject: [PATCH 6/8] =?UTF-8?q?[CHORE]=20:=20=EC=8A=A4=ED=81=AC=EB=9E=A9,?= =?UTF-8?q?=20=EC=83=81=EC=84=B8=EB=B3=B4=EA=B8=B0,=20=EC=9E=A5=EC=86=8C?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/datamap/dmController.js | 10 +++++----- src/app/datamap/dmRoute.js | 2 +- src/app/datamap/dmdao.js | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app/datamap/dmController.js b/src/app/datamap/dmController.js index 7e4c716..e44a990 100644 --- a/src/app/datamap/dmController.js +++ b/src/app/datamap/dmController.js @@ -226,12 +226,12 @@ exports.deleteScrap = async function (req, res) { * [GET] /app/list/:sortby */ -exports.getCityDataList = async function (req, res) { - const sortBy = req.query.sortby; - +exports.getCityList = async function (req, res) { + const sortBy = req.params.sortby; try { - const cityDataList = await dmService.createCityList(sortBy); - return res.send(cityDataList); + const cityList = await dmService.createCityList(sortBy); + console.log(cityList); + return res.send(cityList); } catch (error) { console.error("Error:", error); return res.sendStatus(500); diff --git a/src/app/datamap/dmRoute.js b/src/app/datamap/dmRoute.js index 5648e7e..f416980 100644 --- a/src/app/datamap/dmRoute.js +++ b/src/app/datamap/dmRoute.js @@ -7,7 +7,7 @@ module.exports = function (app) { app.get("/app/pinclick/:code/details", datamap.getDetails); // app.get("/app/citydata/details/:category", datamap.getCityDataByCategory); // app.get("/app/citydata/details/fcst", datamap.getFcstData); - app.get("/app/citydata/list", datamap.getCityDataSorted); + app.get("/app/list/:sortby", datamap.getCityList); // 임의로 라우터 uri를 정한거라 편하신대로 수정하셔도 괜찮습니다! // 데이터 지도 스크랩 app.post("/app/map/:place_id/scrap", datamap.postScrap); diff --git a/src/app/datamap/dmdao.js b/src/app/datamap/dmdao.js index df5f4cb..1e51087 100644 --- a/src/app/datamap/dmdao.js +++ b/src/app/datamap/dmdao.js @@ -140,10 +140,10 @@ async function selectCityList(connection, sortBy) { let orderByClause = ""; if (sortBy === "high") { orderByClause = - 'ORDER BY FIELD(CONGEST_LVL, "붐빔", "약간 붐빔", "보통", "여유")'; + 'ORDER BY FIELD(AREA_CONGEST_LVL, "붐빔", "약간 붐빔", "보통", "여유")'; } else if (sortBy === "low") { orderByClause = - 'ORDER BY FIELD(CONGEST_LVL, "여유", "보통", "약간 붐빔", "붐빔")'; + 'ORDER BY FIELD(AREA_CONGEST_LVL, "여유", "보통", "약간 붐빔", "붐빔")'; } else if (sortBy === "name") { orderByClause = "ORDER BY AREA_NM"; } From 907689a25ba051e76fa3c2880dc01e5a4c26ceaf Mon Sep 17 00:00:00 2001 From: moonyaeyoon Date: Fri, 18 Aug 2023 09:41:33 +0900 Subject: [PATCH 7/8] =?UTF-8?q?=E2=9C=A8=20[FEAT]=20:=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=EB=B3=B4=EA=B8=B0,=20=EC=8A=A4=ED=81=AC=EB=9E=A9,=20=EC=9E=A5?= =?UTF-8?q?=EC=86=8C=20=EB=AA=A9=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/PinView/pinViewDao.js | 1 + src/app/datamap/dmController.js | 65 ++++++++------ src/app/datamap/dmProvider.js | 48 ++++++++--- src/app/datamap/dmRoute.js | 23 +++-- src/app/datamap/dmService.js | 41 +++++++-- src/app/datamap/dmdao.js | 148 +++++++++++++++++++++++--------- 6 files changed, 233 insertions(+), 93 deletions(-) diff --git a/src/app/PinView/pinViewDao.js b/src/app/PinView/pinViewDao.js index 9969dab..471444b 100644 --- a/src/app/PinView/pinViewDao.js +++ b/src/app/PinView/pinViewDao.js @@ -186,6 +186,7 @@ async function deletePinLikeUser(connection, pinId, userId) { module.exports = { insertPin, selectPin, + insertNearByPin, selectPinById, deleteRecentPin, insertRecentPin, diff --git a/src/app/datamap/dmController.js b/src/app/datamap/dmController.js index e44a990..2be5ec2 100644 --- a/src/app/datamap/dmController.js +++ b/src/app/datamap/dmController.js @@ -74,8 +74,8 @@ async function getCategoryData(category) { categoryUrls = urls[category] || []; } - const responsePromises = categoryUrls.map(async (code) => { - const url = `http://openapi.seoul.go.kr:8088/72655a6f586a6a7539344e4a6f6755/xml/citydata/1/5/${code}`; + const responsePromises = categoryUrls.map(async (placeId) => { + const url = `http://openapi.seoul.go.kr:8088/72655a6f586a6a7539344e4a6f6755/xml/citydata/1/5/${placeId}`; const response = await axios.get(url); const xmlData = response.data; const jsonData = convert.xml2json(xmlData, { compact: true, spaces: 4 }); @@ -85,23 +85,28 @@ async function getCategoryData(category) { // cityData가 undefined인 경우 빈 객체로 초기화 return { - CODE: code, - CATEGORY: category, - AREA_NM: cityData ? cityData["AREA_NM"]["_text"] : "", - AREA_CONGEST_LVL: cityData + placeId: placeId, + category: category, + placeName: cityData ? cityData["AREA_NM"]["_text"] : "", + congestLVL: cityData ? cityData["LIVE_PPLTN_STTS"]["LIVE_PPLTN_STTS"]["AREA_CONGEST_LVL"][ "_text" ] : "", - AREA_CONGEST_MSG: cityData + congestFgrs: cityData + ? cityData["LIVE_PPLTN_STTS"]["LIVE_PPLTN_STTS"]["AREA_PPLTN_MAX"][ + "_text" + ] + : "", + congestMSG: cityData ? cityData["LIVE_PPLTN_STTS"]["LIVE_PPLTN_STTS"]["AREA_CONGEST_MSG"][ "_text" ] : "", - AREA_DATA_TIME: cityData + dataTime: cityData ? cityData["LIVE_PPLTN_STTS"]["LIVE_PPLTN_STTS"]["PPLTN_TIME"]["_text"] : "", - FCST_PPLTN: cityData + fcstData: cityData ? cityData["LIVE_PPLTN_STTS"]["LIVE_PPLTN_STTS"]["FCST_PPLTN"] : [], }; @@ -132,7 +137,6 @@ exports.getAllCityData = async function (req, res) { const categoryData = await allCategoryData[category]; dmProvider.updateAllCityData(categoryData); }); - return res.send(response(responseStatus.SUCCESS, allCategoryData)); } catch (error) { console.error("Error:", error); @@ -142,14 +146,14 @@ exports.getAllCityData = async function (req, res) { /** * API No. 2 * Name: 지도에서 마커 클릭 조회 API - * [GET] /app/pinclick/:code + * [GET] /app/pinclick/:placeId */ -exports.getpinclickByCode = async function (req, res) { - const placeCode = req.params.code; // URL 파라미터에서 이름 가져오기 +exports.getpinclickByplaceId = async function (req, res) { + const placeId = req.params.placeId; // URL 파라미터에서 이름 가져오기 try { - const placeData = await dmService.createclickPin(placeCode); - console.log("Place Data:", placeData); // 결과값 콘솔에 출력 + const placeData = await dmService.createpinClick(placeId); + console.log("Place Data:", placeData); return res.send(response(responseStatus.SUCCESS, placeData)); } catch (error) { @@ -159,20 +163,27 @@ exports.getpinclickByCode = async function (req, res) { }; /** * API No. 3 - * Name: 상세보기 - * [GET] /app/pinclick/:code/details + * Name: 상세보기 API (장소 정보, 추천장소, 혼잡도 전망 - 추후 12시간 + 최대) + * [GET] /app/pinclick/:placeId/details */ exports.getDetails = async function (req, res) { - const placeCode = req.params.code; + const placeId = req.params.placeId; try { - const { markerDetails, recommendationPlaces } = - await dmService.createDetails(placeCode); + const { markerDetails, fcstData, maxfcst, recommendationPlaces } = + await dmService.createDetails(placeId); console.log("Marker Details:", markerDetails); - console.log("Random Places:", recommendationPlaces); + console.log("FcstData", fcstData); + console.log("MAX", maxfcst); + console.log("Recommend Places:", recommendationPlaces); return res.send( - response(responseStatus.SUCCESS, { markerDetails, recommendationPlaces }) + response(responseStatus.SUCCESS, { + markerDetails, + fcstData, + maxfcst, + recommendationPlaces, + }) ); } catch (error) { console.error("Error:", error); @@ -184,11 +195,11 @@ exports.getDetails = async function (req, res) { /** * API No.4 * Name: 데이터 지도 스크랩 - * [POST] /app/map/:place_id/scrap + * [POST] /app/:placeId/scrap */ exports.postScrap = async function (req, res) { const userId = req.verifiedToken.userId; // 현재 로그인한 userId - const placeId = req.params.place_id; + const placeId = req.params.placeId; console.log(userId, placeId); const scrapResult = await dmService.createScrap(userId, placeId); return res.send(response(responseStatus.SUCCESS, scrapResult)); @@ -208,11 +219,11 @@ exports.getScrap = async function (req, res) { /** * API No.6 * Name: 스크랩 삭제 - * [DELETE] /app/map/:place_id/scrap + * [DELETE] /app/:placeId/scrap */ exports.deleteScrap = async function (req, res) { const userId = req.verifiedToken.userId; // 현재 로그인한 userId - const placeId = req.params.place_id; + const placeId = req.params.placeId; // if (!placeId) return res.send(errResponse(baseResponse.SCRAP_PLACEID_EMPTY)); @@ -222,7 +233,7 @@ exports.deleteScrap = async function (req, res) { /** * API No. 7 - * Name: 장소 목록 API (혼잡도 높은순, 혼잡도 낮은순, 가나다순) + * Name: 장소 목록 API (혼잡도 높은순(default), 혼잡도 낮은순, 가나다순) * [GET] /app/list/:sortby */ diff --git a/src/app/datamap/dmProvider.js b/src/app/datamap/dmProvider.js index 2d56f72..ea1cf28 100644 --- a/src/app/datamap/dmProvider.js +++ b/src/app/datamap/dmProvider.js @@ -1,7 +1,8 @@ const { pool } = require("../../../config/database"); const dmDao = require("./dmDao"); +const pinViewDao = require("./pinViewDao"); -// citydata 테이블의 모든 데이터를 삭제하고 새로운 데이터를 추가하는 함수 +// citydata 테이블 업데이트 async function updateAllCityData(categoryData) { try { const connection = await pool.getConnection(async (conn) => conn); @@ -14,7 +15,7 @@ async function updateAllCityData(categoryData) { } } -//스크랩 +//스크랩 조회 (mypage) async function retrieveScrap(userId) { const connection = await pool.getConnection(async (conn) => conn); const scrapResult = await dmDao.selectScraps(connection, userId); @@ -23,16 +24,36 @@ async function retrieveScrap(userId) { return scrapResult; } -//상세보기 조회 (장소 정보, 혼잡도 전망, 추천장소) -async function retrieveDetails(placeCode) { +//상세보기 조회 (장소 정보, 혼잡도 전망, 작성된 인근핀, 추천장소) +//12시간 전 혼잡도는 공공데이터 출력값에 없어서 구현 고민 중입니다... DB에 시간대별로 저장해두고 업데이트 하는 방식...? +// +async function retrieveDetails(placeId) { try { const connection = await pool.getConnection(async (conn) => conn); - const markerDetails = await dmDao.selectMarkerDetails( - connection, - placeCode - ); - const category = markerDetails[0].CATEGORY; + //장소 정보 + const markerDetails = await dmDao.selectMarkerDetails(connection, placeId); + + //혼잡도 전망 : 그래프 + const fcstData = []; + for (let index = 0; index < 12; index++) { + const result = await dmDao.selectFcstData(connection, index, placeId); + fcstData.push(result[0]); + } + + //혼잡도 전망 : 향후 12시간 중 최대 혼잡 시간 + let maxfcst = fcstData[0]; + for (let i = 1; i < fcstData.length; i++) { + if (fcstData[i].fcstMax > maxfcst.fcstMax) { + maxfcst = fcstData[i]; + } + } + + //작성된 인근핀 + const nearbyPins = await dmDao.selectNearbyPins(connection, placeId); + + //추천 장소 + const category = markerDetails[0].category; console.log("마커카테고리", category); const recommendationPlaces = await dmDao.selectRecommendationPlaces( connection, @@ -40,11 +61,18 @@ async function retrieveDetails(placeCode) { ); connection.release(); - return { markerDetails, recommendationPlaces }; + return { + markerDetails, + fcstData, + maxfcst, + nearbyPins, + recommendationPlaces, + }; } catch (error) { throw error; } } + //장소 목록 async function retrieveCityList(sortBy) { const connection = await pool.getConnection(async (conn) => conn); diff --git a/src/app/datamap/dmRoute.js b/src/app/datamap/dmRoute.js index f416980..355cec6 100644 --- a/src/app/datamap/dmRoute.js +++ b/src/app/datamap/dmRoute.js @@ -3,17 +3,22 @@ module.exports = function (app) { // 공공데이터 API app.get("/app/citydata", datamap.getAllCityData); - app.get("/app/pinclick/:code", datamap.getpinclickByCode); - app.get("/app/pinclick/:code/details", datamap.getDetails); - // app.get("/app/citydata/details/:category", datamap.getCityDataByCategory); - // app.get("/app/citydata/details/fcst", datamap.getFcstData); + + // 마커클릭했을 때 API + app.get("/app/pinclick/:placeId", datamap.getpinclickByplaceId); + + //상세보기 API + app.get("/app/pinclick/:placeId/details", datamap.getDetails); + + // 장소 목록 API app.get("/app/list/:sortby", datamap.getCityList); - // 임의로 라우터 uri를 정한거라 편하신대로 수정하셔도 괜찮습니다! + // 데이터 지도 스크랩 - app.post("/app/map/:place_id/scrap", datamap.postScrap); + app.post("/app/:placeId/scrap", datamap.postScrap); + //스크랩 삭제 - app.delete("/app/map/:place_id/scrap", datamap.deleteScrap); - // 스크랩 조회의 경우 프론트 단에선 mypage에서 이뤄지는 것 같은데 백에선 같은 데이터 지도 스크랩 파트라 함께 올립니다! - // 스크랩 조회 + app.delete("/app/:placeId/scrap", datamap.deleteScrap); + + // 스크랩 조회 (마이페이지 - 백엔드 데이터 지도 스크랩 파트 포함 ) app.get("/app/myPage/scrap", datamap.getScrap); }; diff --git a/src/app/datamap/dmService.js b/src/app/datamap/dmService.js index 4ea84c0..37a57ad 100644 --- a/src/app/datamap/dmService.js +++ b/src/app/datamap/dmService.js @@ -8,11 +8,11 @@ const dmController = require("./dmController"); const { pool } = require("../../../config/database"); //마커 클릭했을 때, 해당 장소 데이터 불러오기 -async function createclickPin(placeCode) { +async function createpinClick(placeId) { try { const connection = await pool.getConnection(async (conn) => conn); //클릭한 장소 정보 불러오기 - const placeData = await dmDao.selectPinDataByCode(connection, placeCode); + const placeData = await dmDao.selectPinDataByCode(connection, placeId); //클릭한 장소 스크랩 connection.release(); @@ -29,6 +29,22 @@ async function createScrap(userId, placeId) { try { const connection = await pool.getConnection(async (conn) => conn); const insertScrapParams = [userId, placeId]; + // 1. 스크랩 가능한 장소 개수 확인 (최대 3개) + const canScrap = await dmDao.checkScrapLimit(connection, userId); + if (!canScrap) { + connection.release(); + return false; // 최대 스크랩 개수 초과로 스크랩 불가능 + } + // 2. 이미 스크랩한 장소인지 확인 + const isAlreadyScrapped = await dmDao.checkIfAlreadyScrapped( + connection, + insertScrapParams + ); + if (isAlreadyScrapped) { + connection.release(); + return false; // 이미 스크랩한 장소인 경우 스크랩 불가능 + } + // 3. 스크랩 가능한 경우, 장소를 스크랩 테이블에 추가 const creatScrapResult = await dmDao.insertScrap( connection, insertScrapParams @@ -63,11 +79,22 @@ async function deleteScrap(userId, placeId) { } //상세보기 -async function createDetails(placeCode) { +async function createDetails(placeId) { try { - const { markerDetails, recommendationPlaces } = - await dmProvider.retrieveDetails(placeCode); - return { markerDetails, recommendationPlaces }; + const { + markerDetails, + fcstData, + maxfcst, + nearbyPins, + recommendationPlaces, + } = await dmProvider.retrieveDetails(placeId); + return { + markerDetails, + fcstData, + maxfcst, + nearbyPins, + recommendationPlaces, + }; } catch (error) { throw error; } @@ -80,7 +107,7 @@ async function createCityList(sortBy) { } module.exports = { - createclickPin, + createpinClick, createScrap, deleteScrap, createDetails, diff --git a/src/app/datamap/dmdao.js b/src/app/datamap/dmdao.js index 1e51087..10ab66c 100644 --- a/src/app/datamap/dmdao.js +++ b/src/app/datamap/dmdao.js @@ -5,21 +5,21 @@ const { pool } = require("../../../config/database"); // 공공데이터 불러오기 async function updateCityData(connection, extractedDataArray) { try { - // 쿼리문 작성 const insertcitydataquery = ` - INSERT INTO citydata (CATEGORY,CODE, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG, AREA_DATA_TIME, FCST_PPLTN) - VALUES (?, ?, ?, ?, ?, ?, ?) + INSERT INTO citydata (placeId,category, placeName, congestLVL, congestFgrs, congestMSG, dataTime, fcstData) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) `; // 모든 데이터를 Promise.all로 처리하여 데이터베이스에 저장 const savePromises = extractedDataArray.map(async (data) => { const values = [ - data.CATEGORY, - data.CODE, - data.AREA_NM, - data.AREA_CONGEST_LVL, - data.AREA_CONGEST_MSG, - data.AREA_DATA_TIME, - JSON.stringify(data.FCST_PPLTN), + data.placeId, + data.category, + data.placeName, + data.congestLVL, + data.congestFgrs, + data.congestMSG, + data.dataTime, + JSON.stringify(data.fcstData), ]; return connection.query(insertcitydataquery, values); }); @@ -53,31 +53,26 @@ async function selectCityData() { } } -//클릭한 마커의 장소 데이터만 불러오기 (by code) -async function selectPinDataByCode(connection, placeCode) { +//클릭한 마커의 장소 정보 조회 (by placeId) +async function selectPinDataByplaceId(connection, placeId) { const selectpinquery = ` - SELECT CODE, CATEGORY, AREA_NM, AREA_CONGEST_LVL, AREA_CONGEST_MSG - FROM citydata - WHERE CODE = ? + SELECT c.placeId, c.category, c.placeName, c.congestLVL, c.congestMSG + FROM citydata c + WHERE c.placeId = ? `; - const [selectpinrows] = await connection.query(selectpinquery, [placeCode]); + const [selectpinrows] = await connection.query(selectpinquery, [placeId]); return selectpinrows; } -/* - * 장소 스크랩 - */ -//스크랩 가능한 장소 개수 확인 (최대 3개) - // 상세보기_클릭한 장소 정보 -async function selectMarkerDetails(connection, placeCode) { +async function selectMarkerDetails(connection, placeId) { const selectMarkerDetailsQuery = ` - SELECT c.CODE, c.CATEGORY, c.AREA_NM, c.AREA_CONGEST_LVL, c.AREA_CONGEST_MSG, c.FCST_PPLTN + SELECT c.placeId, c.category, c.placeName, c.congestLVL, c.congestMSG FROM citydata c - WHERE c.CODE = ?; + WHERE c.placeId = ?; `; const [markerDetailsRows] = await connection.query(selectMarkerDetailsQuery, [ - placeCode, + placeId, ]); return markerDetailsRows; } @@ -85,9 +80,9 @@ async function selectMarkerDetails(connection, placeCode) { // 상세보기_클릭한 장소와 동일 카테고리 장소 추천 (3곳) async function selectRecommendationPlaces(connection, category, limit = 3) { const selectRecommendationPlacesQuery = ` - SELECT c.CATEGORY, c.AREA_NM, c.AREA_CONGEST_LVL + SELECT c.category, c.placeName, c.congestLVL FROM citydata c - WHERE c.CATEGORY = ? + WHERE c.category = ? ORDER BY RAND() LIMIT ?; `; @@ -98,13 +93,56 @@ async function selectRecommendationPlaces(connection, category, limit = 3) { return recommendationPlacesRows; } +//혼잡도 전망 조회 (12시간 후 까지) +async function selectFcstData(connection, index, placeId) { + const selectFcstquery = ` + SELECT + JSON_UNQUOTE(JSON_EXTRACT(fcstData, CONCAT('$.FCST_PPLTN[', ? ,'].FCST_TIME._text'))) AS fcstTime, + CAST(JSON_UNQUOTE(JSON_EXTRACT(fcstData, CONCAT('$.FCST_PPLTN[', ? ,'].FCST_PPLTN_MAX._text'))) AS UNSIGNED) AS fcstMax, + CAST(JSON_UNQUOTE(JSON_EXTRACT(fcstData, CONCAT('$.FCST_PPLTN[', ? ,'].FCST_PPLTN_MIN._text'))) AS UNSIGNED) AS fcstMin, + JSON_UNQUOTE(JSON_EXTRACT(fcstData, CONCAT('$.FCST_PPLTN[', ? ,'].FCST_CONGEST_LVL._text'))) AS fcstCongestLVL + FROM citydata c + WHERE c.placeId = ?; + `; + const values = [placeId]; + try { + const [fcstRows] = await connection.query(selectFcstquery, [ + index, + index, + index, + index, + values, + ]); + return fcstRows; + } catch (error) { + throw error; + } +} + +// 인근 핀 조회 +async function selectNearbyPins(connection, placeId) { + const selectNearbyPinsQuery = ` + SELECT n.pinId, n.pinCongest, n.createdAt + FROM nearByPin n + WHERE placeId = ?; + `; + try { + const [nearbyPinsRows] = await connection.query( + selectNearbyPinsQuery, + placeId + ); + return nearbyPinsRows; + } catch (error) { + throw error; + } +} + // erd cloud에 업로드한 table 형태 참고해서 insert하고 select하도록 했습니다! 편하신대로 수정하셔도 괜찮습니다! async function insertScrap(connection, insertScrapParams) { const insertQuestionQuery = ` - INSERT INTO scrap(userId, place_id) + INSERT INTO scrap(userId, placeId) VALUES(?, ?); `; - const insertScrapRows = await connection.query( insertQuestionQuery, insertScrapParams @@ -112,11 +150,37 @@ async function insertScrap(connection, insertScrapParams) { return insertScrapRows; } +// 스크랩 가능한 장소 개수 확인 (최대 3개) +async function selectScrapLimit(connection, userId) { + const selectScrapCountQuery = ` + SELECT COUNT(*) AS count + FROM scrap s + WHERE s.userId = ? + `; + const [selectScrapCountrows] = await connection.query( + selectScrapCountQuery, + userId + ); + const currentScrapCount = selectScrapCountrows[0].count; + return currentScrapCount < 3; // 최대 스크랩 가능 개수는 3개 +} + +// 이미 스크랩한 장소인지 확인 +async function selectisScrapped(connection, placeId) { + const selectisScrappedQuery = ` + SELECT * FROM scrap WHERE userId = ? AND placeId =? + `; + const [isScrappedrows] = await connection.query(selectisScrappedQuery, [ + placeId, + ]); + return isScrappedrows.length > 0; +} + // scrap 테이블에 저장된 place_id로 db에 저장된 citydata를 조회하도록 했습니다! async function selectScraps(connection, userId) { const selectScrapsQuery = ` - SELECT c.area_nm, c.road_addr, c.area_congest_lvl - FROM citydata c JOIN scrap s ON c.place_id = s.place_id + SELECT c.placeName, c.congestLVL + FROM citydata c JOIN scrap s ON c.placeId = s.placeId where s.userId = ?; `; const [questionRow] = await connection.query(selectScrapsQuery, userId); @@ -126,7 +190,7 @@ async function selectScraps(connection, userId) { async function deleteScrap(connection, deleteScrapParams) { const deleteQuestionQuery = ` DELETE FROM scrap - WHERE userId = ? AND place_id =?; + WHERE userId = ? AND placeId =?; `; const deleteQuestionRows = await connection.query( deleteQuestionQuery, @@ -135,21 +199,21 @@ async function deleteScrap(connection, deleteScrapParams) { return deleteQuestionRows; } -//장소 목록 +//장소 목록 (혼잡도 높은 순(default), 낮은 순, 가나다 순) async function selectCityList(connection, sortBy) { let orderByClause = ""; if (sortBy === "high") { orderByClause = - 'ORDER BY FIELD(AREA_CONGEST_LVL, "붐빔", "약간 붐빔", "보통", "여유")'; + 'ORDER BY FIELD(congestLVL, "붐빔", "약간 붐빔", "보통", "여유"), congestFgrs DESC'; //congestLVL이 동일한 경우 congestFgrs 숫자가 큰 순서대로 } else if (sortBy === "low") { - orderByClause = - 'ORDER BY FIELD(AREA_CONGEST_LVL, "여유", "보통", "약간 붐빔", "붐빔")'; + orderByClause = orderByClause = + 'ORDER BY FIELD(congestLVL, "여유", "보통", "약간 붐빔", "붐빔"), congestFgrs ASC'; //congestLVL이 동일한 경우 congestFgrs 숫자가 작은 순서대로 } else if (sortBy === "name") { - orderByClause = "ORDER BY AREA_NM"; + orderByClause = "ORDER BY placeName"; } const selectCityListQuery = ` - SELECT AREA_NM, AREA_CONGEST_LVL - FROM citydata + SELECT c.placeName, c.congestLVL + FROM citydata c ${orderByClause}; `; const [cityListRows] = await connection.query(selectCityListQuery); @@ -160,11 +224,15 @@ module.exports = { deleteAllCityData, updateCityData, selectCityData, - selectPinDataByCode, + selectPinDataByplaceId, + selectScrapLimit, + selectisScrapped, insertScrap, selectScraps, deleteScrap, selectMarkerDetails, + selectFcstData, + selectNearbyPins, selectRecommendationPlaces, selectCityList, }; From 1257913fc9473f3f8d5acef8364bc920ceddbc68 Mon Sep 17 00:00:00 2001 From: moonyaeyoon Date: Mon, 21 Aug 2023 13:35:21 +0900 Subject: [PATCH 8/8] =?UTF-8?q?[=E2=99=BB=EF=B8=8F=20Refactoring]=20:=20?= =?UTF-8?q?=ED=95=80=20=ED=81=B4=EB=A6=AD,=20=EC=83=81=EC=84=B8=EB=B3=B4?= =?UTF-8?q?=EA=B8=B0,=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20,=20=EC=9E=A5?= =?UTF-8?q?=EC=86=8C=20=EB=AA=A9=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/datamap/dmProvider.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/datamap/dmProvider.js b/src/app/datamap/dmProvider.js index ea1cf28..3d4f80a 100644 --- a/src/app/datamap/dmProvider.js +++ b/src/app/datamap/dmProvider.js @@ -1,6 +1,6 @@ const { pool } = require("../../../config/database"); const dmDao = require("./dmDao"); -const pinViewDao = require("./pinViewDao"); +const pinViewDao = require("../../app/PinView/pinViewDao"); // citydata 테이블 업데이트 async function updateAllCityData(categoryData) { @@ -50,7 +50,7 @@ async function retrieveDetails(placeId) { } //작성된 인근핀 - const nearbyPins = await dmDao.selectNearbyPins(connection, placeId); + const nearbyPins = await pinViewDao.selectNearbyPins(connection, pinId); //추천 장소 const category = markerDetails[0].category;