페어 활동 기록_Day11_윤우_현정 - boostcampwm-2022/web33-Mildo GitHub Wiki

✂️ 분배된 이슈

  • 서울 도시 데이터 비동기 처리로 속도 향상
  • MongoDB 연결
  • 데이터를 가공해서 DB에 저장하기(CRUD)

🚩 구현 목표

  • 서울 실시간 도시 데이터 속도를 향상한다.
  • 데이터베이스와 연결하여 저장한다.
  • 주요 50곳의 장소의 위도/경도를 처리한다.

🍀 세부 목표

  • 서울 도시 데이터 50개를 불러올 때 Promise를 이용해서 비동기 처리
  • controller, service 분리
  • mongoose를 이용해서 MongoDB와 연결
  • 스키마 생성
    • 장소
    • 밀도
  • 데이터 저장

🖥️ 구현 내용

장소 10곳 동기처리

image

image

  • 1차 시도 : 26.73초
  • 2차 시도 : 25.57초

장소 10곳 비동기처리

image

  • 50곳 시도 : 15.02초

image

image

  • 10곳 1차 시도 : 6.04초
  • 10곳 2차 시도 : 5.70초
  • 속도가 향상되지만 몇몇 장소의 데이터를 못 불러오는 현상이 발생한다.

⇒ 다시 동기 처리로 변경

📖 학습 내용

Mongoose insertMany

  • 배열에 있는 데이터를 map 으로 돌리면서 하나하나 insert해주면 시간이 오래 걸림
  • insertMany : 배열에 있는 데이터를 통째로 insert해주는 메소드
DataSchema.insertMany(dataArray)
.then(() => {
  console.log('data inserted');
})
.catch(e => {
  console.log(e);
});

🩺 의사결정

MongoDB 스키마 설계

  1. 다 때려박기
    • 문제점
      • 장소명, 위도, 경도가 중복되어서 들어감
    • 장점
      • 구현이 쉬움
      • NoSQL의 장점을 살릴 수 있음
  2. Embeded
    • 문제점
      • 하나의 필드값이 무한으로 커짐
      • 이럴 때는 차라리 Reference를 사용하는 것이 낫다고 함
    • 장점
      • 테이블 상태를 한 번에 볼 수 있음
  3. Reference
    • 문제점
      • 장소명, 위도, 경도 이외에는 중복되는 값이 없어 이것 때문에 참조를 해야 될까란 의문
      • 관계가 많아지면 sql보다 느려질 수 있음
      • 성능 등 MongoDB의 장점을 살릴 수 없음
    • 장점
      • 중복되는 값(장소명, 위도/경도)을 계속 추가하지 않아도 됨

주요 장소 데이터 위치

  1. 서버에서 상수로 갖고 사용하기 → 다 때려박기로 사용하기 좋아보임
    1. 데이터베이스에 저장 X
    2. 데이터베이스에 저장
  2. 데이터베이스에 넣어서 사용하기
    • reference로 사용하기 좋아보임

    • reference로 사용하지 않아도 됨

      • 장소 다큐먼트(장소명, 좌표) → 고정
        • 핀 그릴 때
        • 주요 장소가 늘어날 때 유지보수가 좋음
      • 밀도 다큐먼트(장소명, 밀도, 인구수, 시간) → api로 계속 찔러옴
        • 밀도, 인구수

      ⇒ 굳이 join하지 않아도 된다.

🚧 Trouble Shooting

Promise 오류

  • 기존 코드

    const cityData: cityDataTypes[] = await Promise.all(
      Object.keys(AREA_NAMES).map(async areaName => {
        const data = await getAxiosSeoulArea(areaName); // Promise.all
        const json = await xml2js.parseStringPromise(data); // Promise.all
    
        if (json['Map']) {
          console.log(`실패: ${areaName}`);
          return {
            areaName: null,
            populationMin: null,
            populationMax: null,
            populationLevel: null,
            updatedAt: null
          };
        }
        
    ...
    
        return {
          areaName: AREA_NM[0],
          populationMin: AREA_PPLTN_MIN[0],
          populationMax: AREA_PPLTN_MAX[0],
          populationLevel: AREA_CONGEST_LVL[0],
          updatedAt: PPLTN_TIME[0]
        };
      })
    );
    
    • 서울 실시간 도시 데이터 API에서 데이터를 받아오는 로직, json으로 변환하는 로직, 데이터를 가공하는 로직이 하나의 Promise.all 에 넣어져 있었음
  • 수정 후 코드

    const cityDataXml = await Promise.all(
      Object.keys(AREA_NAMES).map(async areaName =>
        getAxiosSeoulArea(areaName)
      )
    );
    
    const cityDataJson = await Promise.all(
      cityDataXml.map(async xml => xml2js.parseStringPromise(xml))
    );
    
    const cityData = cityDataJson.map(json => {
      if (json['Map']) {
        console.log(`실패`);
        return {
          areaName: null,
          populationMin: null,
          populationMax: null,
          populationLevel: null,
          updatedAt: null
        };
      }
    
      ...
    
      return {
        areaName: AREA_NM[0],
        populationMin: AREA_PPLTN_MIN[0],
        populationMax: AREA_PPLTN_MAX[0],
        populationLevel: AREA_CONGEST_LVL[0],
        updatedAt: PPLTN_TIME[0]
      };
    });
    
    • 서울 실시간 도시 데이터 API에서 데이터를 받아오는 로직과 json으로 변환하는 로직을 각각의 Promise.all로 처리한 후 데이터 가공은 따로 map 을 사용하여 처리

    • 10장소씩은 성공하는 듯 보였지만 이전과 차이 없이 데이터를 가져오지 못하고 있다. 서울시 공공데이터 API에서 오류가 발생하여 다시 동기 처리로 바꾸어야 했다.

      image

❓ 궁금한 점

🎸 기타

인덱싱으로 mongoDB 성능 향상시키기

  • Population 스키마에서 장소명을 인덱싱하면 이후 탐색할때 속도 향상을 체감할 수 있을 것 같다.