일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- Sequelize
- Android
- precourse
- code states
- 이머시브
- immersive
- build
- Object.create()
- codestates
- 외부API
- react-native
- Dictionary
- 코드 스테이츠
- git
- deploy
- 아마데우스API
- immersiva
- 프리코스_멤버십
- apk파일
- 이머시브코스
- react-natiave
- IntelliJ
- 프리코스
- refresh token
- token
- react-navigation
- 코딩부트캠프
- 코드스테이츠후기
- for loop
- 코드스테이츠
- Today
- Total
TIL 블로그
트렌드 데이터를 수집하고 내려주기 본문
여행 계산기는 어플 사용자들의 검색 기록을 모아서 트렌드 데이터를 제공하는 기능이 있다.
이를 위해서 견적 조회를 할 때 연령, 성별, 관심사를 입력받고,
트렌드 화면에서는 이를 바탕으로 필터링을 하여 가장 인기가 높은 여행지를 제공한다.
그렇게 어려운 기능은 아닌 것 같지만, 그래도 어떻게 했는지 한 번 정리해보고
리팩토링할 수 있는 부분이 있다면 연구해보는 포스팅.
1. calculate.js 에서 견적 조회가 실행되면 trend 테이블을 업데이트한다.
// 히스토리 데이터 업데이트하기 (여기는 로그인한 사용자가 본인의 검색 기록을 조회할 수 있도록 업데이트)
if (name) {
db.Userhistory.create({ username: name, departuredate: departure, arrivaldate: arrival, city: cityName, estimate: JSON.stringify(response.estimate), photo: historyphoto });
}
//트렌드 데이터 업데이트하기
db.Trend.findOne({ where: { keyword: keyword, gender: gender, age: age, iataCode: cityName } }) // DB 로부터 해당 조합의 현재 count 수를 찾는다.
.then(data => {
console.log(`[검색 시 트렌드 DB 업데이트] [조합코드] keyword : ${keyword}, gender : ${gender}, iataCode : ${cityName}`)
console.log('[검색 시 트렌드 DB 업데이트] [도시명 및 카운트]', data.dataValues)
let count = data.dataValues.count;
count = count + 1; // 해당 조합의 현재 count 수에 +1 을 한다.
db.Trend.update({ count: count }, { where: { keyword: keyword, gender: gender, age: age, iataCode: cityName } }) // +1 된 count 수를 해당 조합에 업데이트한다.
})
}
구현한 방법
db에서 Trend 테이블에서 keyword, age, gender 조건에 맞는 데이터를 불러와서 count + 1 해서 업데이트함.
리팩토링한다면 ?
찾아보니까 sequelize 는 increment 라는 메소드가 따로 있네? ㅋㅋㅋ 그 때는 왜 이런 것도 못 찾았을까. 사실 이런 게 있을거라고 생각도 못한 것 같다. 왜지? db니까 있을 법도 한데.. 하튼 이제라도 알았으니까 됐다.
아래는 공식문서의 예시이다.
Example:
increment number by 1
Model.increment('number', { where: { foo: 'bar' });
increment number and count by 2
Model.increment(['number', 'count'], { by: 2, where: { foo: 'bar' } });
increment answer by 42, and decrement tries by 1
// `by` is ignored, as each column has its own value
Model.increment({ answer: 42, tries: -1}, { by: 2, where: { foo: 'bar' } });
1씩 증가시키면 되니까 아래처럼 쓰면 될 것 같다.
db.Trend.increment('count' , { where : { keyword: keyword, gender: gender, age: age,iataCode: cityName } })
이렇게 사용자가 여행지를 검색해서 조회할 때마다 우리의 db에 데이터가 쌓인다!
2. 이제 사용자가 keyword, age, gender 를 넣고 트렌드 데이터를 검색했을 때, 가장 인기있는 도시를 알려줘야 한다.
도시명, count, ratio, 도시사진까지 클라이언트에게 전달했다.
아래는 나름 MVC 패턴을 이용해서 구현한 파일들이다.
routes.js
const express = require('express');
const router = express.Router();
const controllers = require('./controllers');
router.get('/trends', controllers.getTrendInfo);
module.exports = router;
controllers.js
우리는 get 요청에서 쿼리를 trends?code=1012&attraction=Museum 이런 식으로 받기로 했다.
1012에서 1000은 keyword, 10은 age, 2는 gender를 의미한다.
controllers에서 이것들을 분리해서 model의 함수에 넣어줬다.
const getTrendInfo = function (req, res) { // /trends?code=1101&attraction=Museum
// 쿼리 분리해서
const keyword = req.query.code.length === 4 ? req.query.code.slice(0, 2) + '00' : req.query.code.slice(0, 1) + '00';
const age = req.query.code.slice(-2)[0] + '0';
const gender = req.query.code.slice(-1);
if (!keyword || !age || !gender) {
res.sendStatus(400);
}
const keyword_string = req.query.attraction
// model로 보내준다.
trends_model.getTrendInfo(keyword, age, gender, keyword_string, (data) => {
res.status(200).send(data);
})
}
Trends.js
const getTrendInfo = function (keyword, age, gender, keyword_string, callback) {
// 아래 sequelize에 넣기 복잡해서 searchOption 객체를 따로 만들어줬다.
let searchOption = {};
searchOption.keyword = keyword;
if (Number(age)) {
searchOption.age = age;
}
if (Number(gender)) {
searchOption.gender = gender;
}
// 조건에 맞는 것들 다 찾아온다 내림차순으로.
db.Trend.findAll({ where: searchOption, order: [['count', 'DESC']], attributes: ['iataCode', 'count'] })
.then(result => {
// trend 객체에 전달할 것들을 집어넣는다. (city, count, ratio)
// 1등만 알려주면 되니까 result[0]만 신경쓰면 된다!
var trend = {};
trend.city = result[0].dataValues.iataCode; //London (LHR)
trend.count = result[0].dataValues.count;
// 비율 계산하기
let countSum = 0;
for (let i = 0; i < result.length; i++) {
countSum += result[i].dataValues.count;
}
trend.ratio = parseInt((trend.count / countSum) * 100);
// 도시 사진도 같이 내려줬다.
db.Meal.findOne({ where: { cityName: result[0].dataValues.iataCode } })
.then(data => {
trend.cityphoto = data.dataValues.photo;
})
})
}
아래는 구현한 화면이다.
3. 랜덤 트렌드 데이터 내려주기
외부 api를 조회하는데 걸리는 로딩시간에 사용자의 이탈이 우려되어
어떻게 할까 생각하다가 우리가 가진 데이터 중에 내려줄 만한 게 있을까? 생각했다.
위에서 검색한 트렌드 데이터를 이 로딩시간에는 랜덤으로 내려주기로 했다.
(지금 생각해보면 그렇게 좋은 방법인지는 모르겠다. 나랑 연령도 성별도 관심사도 다른 사람들의 인기 여행지 정보를 보여주는게 의미가 있을까?)
하지만 데이터 크롤링을 하지 않은 우리에게 방법은 없었다. (데이터 크롤링 공부해서 꼭 포스팅하기)
randomtrends.js
var db = require("../../models/index");
async function getRandomTrendInfo(callback) {
let response = [];
for (let i = 0; i < 10; i++) {
// 랜덤 숫자 생성하기
let trend = {};
let keywordcode = (Math.floor(Math.random() * (13 - 1 + 1)) + 1) * 100;
let agecode = (Math.floor(Math.random() * (5 - 1 + 1)) + 1) * 10;
let gendercode = Math.floor(Math.random() * (2 - 1 + 1)) + 1;
console.log(`keywordcode : ${keywordcode} / agecode : ${agecode} / gendercode : ${gendercode}`);
let searchOption = {};
searchOption.keyword = keywordcode; // 100
searchOption.age = agecode; // 10
searchOption.gender = gendercode; // 1
await db.Trend.findOne({ where: searchOption, order: [['count', 'DESC']], attributes: ['iataCode', 'count'] })
.then((result) => {
trend.city = result.dataValues.iataCode;
trend.count = result.dataValues.count;
}
);
// 1111을 오로라, 10대, 여성으로 변환하는 과정.
// db에 다녀올까 생각했는데, 괜히 시간만 잡아먹어서 그냥 배열에 넣었다.
var keywordarr = ['오로라', '유적', '맛집', '문화예술', '마사지', '비치', '산림욕', '플리마켓', '아울렛', '쇼핑', '서핑', '캠핑', '호캉스']
var agearr = ['10대', '20대', '30대', '40대', '50대']
var genderarr = ['여성', '남성']
trend.keyword = keywordarr[(keywordcode / 100) - 1]
trend.age = agearr[(agecode / 10) - 1]
trend.gender = genderarr[gendercode - 1]
response.push(trend);
}
callback(response);
}
아래는 구현한 화면이다
이런 식으로 유저들의 정보를 간단하게 저장하고 필터링해서 트렌드 정보를 만들어보았다 ㅎㅎ
'First Project' 카테고리의 다른 글
외부 API 사용하는 방법 (amadeus 항공권 api) (1) | 2019.12.13 |
---|---|
express-session 이용하여 로그인 기능 구현하기 (0) | 2019.12.13 |
[First Project] 마무리하기 (Traverl Calculator) (0) | 2019.12.13 |