- Today
- Total
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Firebase
- 차트
- 채팅
- 리액트
- apollo
- 주식
- error
- nextjs
- 차트만들기
- 3주차
- 항해99
- typescript
- 에러
- Redux
- 비전공자
- typeorm
- javascript
- 차트구현
- react
- graphql
- chart
- Coin
- Flutter
- rtk
- 주식차트
- API
- 코인차트
- websocket
- nestjs
- 코인
Act99 기술블로그
[Nestjs] CSV 파일을 postgresql 테이블로 옮기고 localhost 에 띄우기 본문
필자는 현재 주식정보를 RestAPI 로 띄운 후, React를 이용해 브라우저 상에서 주식 차트를 구현시키려고 한다.
프론트엔드 공부를 하려했지만, 주식 api를 직접 빌드해서 사용하고 싶었기 때문에 작업을 시작했다.
DB 관리는 postgresql 로 할 예정이며, Graphql 과 Typeorm, Nestjs 를 이용할 예정이다.
(Nestjs를 배울 때 이 방식으로 배웠기 때문이기도 하며,
Nestjs Doc을 보면 Typeorm과 Graphql 사용을 권장한다고 적혀있다.)
** postgresql 테이블에 CSV파일을 import 하고 nestjs와 연결하려면 Table을 직접 만드는게 아니라 Nestjs 를 이용해 table을 만들어주어야한다. ** (테이블을 미리 만들어놓고하다가 연동이 안되서 1시간을 잡아먹었다.)
먼저해야할 일은 NestJs에서 모듈을 만드는 일이다.
테스트용으로 가져온 주식 정보는 gs 주식이기 때문에 모듈이름을 stock-gs 로 지었다.
$ nest g mo stock-gs
다음으로 Service 와 Resolver, Entity 를 만들어준다. (graphql을 이용해 데이터들을 불러올 것이기 때문에 Resolver를 필수로 만들어야 한다. )
entity의 경우 내가 가져올 CSV 파일 Column 명에 맞추어 작성했다.
Entity는 꼭 @PrimaryGeneratedColumn이 필요하며 없을 경우 에러가 생긴다.
작성한 결과는 다음과 같다. (Column이 많아서 좀 깁니다.)
- stock-gs.entity.ts
import { Field, Float, InputType, ObjectType } from '@nestjs/graphql';
import {
IsBoolean,
IsNumber,
IsOptional,
IsString,
isString,
} from 'class-validator';
import { CoreEntity } from 'src/common/entities/core.entity';
import { Users } from 'src/users/entities/users.entity';
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
// 만약 dto 부분에 omittype에 inputtype 으로 호출하라 라는 명령어가 없다면 아래를 써줘야함.
// @InputType({isAbstract:true})
// @Field() => 얘는 graphql 데코레이션이며
// @Column(), @ManyToOne() => 얘는 typeorm 데코레이션임
@ObjectType()
@Entity()
export class Gs {
@PrimaryGeneratedColumn()
@Field((type) => Number)
@IsNumber()
id: number;
@Field((type) => Number)
@Column()
@IsString()
index: number;
@Field((type) => Number)
@Column()
@IsNumber()
date: number;
@Field((type) => String)
@Column()
@IsString()
check_item: string;
@Field((type) => Number)
@Column()
@IsNumber()
code: number;
@Field((type) => String)
@Column()
@IsString()
code_name: string;
@Field((type) => Float)
@Column('float')
@IsNumber()
d1_diff_rate: number;
@Field((type) => Number)
@Column()
@IsNumber()
close: number;
@Field((type) => Number)
@Column()
@IsNumber()
open: number;
@Field((type) => Number)
@Column()
@IsNumber()
high: number;
@Field((type) => Number)
@Column()
@IsNumber()
low: number;
@Field((type) => Number)
@Column()
@IsNumber()
volume: number;
@Field((type) => Number)
@Column()
@IsNumber()
clo5: number;
@Field((type) => Number)
@Column()
@IsNumber()
clo10: number;
@Field((type) => Number)
@Column()
@IsNumber()
clo20: number;
@Field((type) => Number)
@Column()
@IsNumber()
clo40: number;
@Field((type) => Number)
@Column()
@IsNumber()
clo60: number;
@Field((type) => Number)
@Column()
@IsNumber()
clo80: number;
@Field((type) => Number)
@Column()
@IsNumber()
clo100: number;
@Field((type) => Number)
@Column()
@IsNumber()
clo120: number;
@Field((type) => Float)
@Column('float')
@IsNumber()
clo5_diff_rate: number;
@Field((type) => Float)
@Column('float')
@IsNumber()
clo10_diff_rate: number;
@Field((type) => Float)
@Column('float')
@IsNumber()
clo20_diff_rate: number;
@Field((type) => Float)
@Column('float')
@IsNumber()
clo40_diff_rate: number;
@Field((type) => Float)
@Column('float')
@IsNumber()
clo60_diff_rate: number;
@Field((type) => Float)
@Column('float')
@IsNumber()
clo80_diff_rate: number;
@Field((type) => Float)
@Column('float')
@IsNumber()
clo100_diff_rate: number;
@Field((type) => Float)
@Column('float')
@IsNumber()
clo120_diff_rate: number;
@Field((type) => Number)
@Column()
@IsNumber()
yes_clo5: number;
@Field((type) => Number)
@Column()
@IsNumber()
yes_clo10: number;
@Field((type) => Number)
@Column()
@IsNumber()
yes_clo20: number;
@Field((type) => Number)
@Column()
@IsNumber()
yes_clo40: number;
@Field((type) => Number)
@Column()
@IsNumber()
yes_clo60: number;
@Field((type) => Number)
@Column()
@IsNumber()
yes_clo80: number;
@Field((type) => Number)
@Column()
@IsNumber()
yes_clo100: number;
@Field((type) => Number)
@Column()
@IsNumber()
yes_clo120: number;
@Field((type) => Number)
@Column()
@IsNumber()
vol5: number;
@Field((type) => Number)
@Column()
@IsNumber()
vol10: number;
@Field((type) => Number)
@Column()
@IsNumber()
vol20: number;
@Field((type) => Number)
@Column()
@IsNumber()
vol40: number;
@Field((type) => Number)
@Column()
@IsNumber()
vol60: number;
@Field((type) => Number)
@Column()
@IsNumber()
vol80: number;
@Field((type) => Number)
@Column()
@IsNumber()
vol100: number;
@Field((type) => Number)
@Column()
@IsNumber()
vol120: number;
}
다음 작업해야하는건 Service이며, 데이터 수정이나 삭제 없이, 정보만 가져올 예정이기 때문에 다음과 같이 작성했다.
- stock-gs.module.ts
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Gs } from './entities/stock-gs.entity';
export class StockGsService {
constructor(@InjectRepository(Gs) private readonly stockGs: Repository<Gs>) {}
getStock(): Promise<Gs[]> {
return this.stockGs.find();
}
}
@InjectRepository 를 사용하지 않으면 Postgresql에 table이 형성되지 않는다.
그 후, resolver를 작성한다. 앞서 말한대로 정보만 가져올 것이기 때문에 @Mutation은 필요 없고 @Query 데코만 사용하면 가능하다.
- stock-gs.resolver.ts
import { Query, Resolver } from '@nestjs/graphql';
import { Gs } from './entities/stock-gs.entity';
import { StockGsService } from './stock-gs.service';
@Resolver((of) => Gs)
export class StockGsResolver {
constructor(private readonly stockGsService: StockGsService) {}
@Query((returns) => [Gs])
gsStock(): Promise<Gs[]> {
return this.stockGsService.getStock();
}
}
resolver 작성이 완료되면 app.module에 연동시켜준다.
resolver와 service는 providers에 넣어준다. (Nestjs provider def 참조)
- stock-gs.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Gs } from './entities/stock-gs.entity';
import { StockGsResolver } from './stock-gs.resolver';
import { StockGsService } from './stock-gs.service';
@Module({
imports: [TypeOrmModule.forFeature([Gs])],
providers: [StockGsResolver, StockGsService],
})
export class StockGsModule {}
app.module.ts 파일에는 자동으로 Stockgs모듈이 import되어있다. (만약 안되어있으면 직접 해야한다.)
TypeOrmModule.forRoot 쪽 entities에 Gs entity를 넣어준다. (Users 는 회원가입까지 가능하게 만들기 위해 필자가 임시로 만들어놓았다.)
TypeOrmModule.forRoot({
type: 'postgres',
host: process.env.DB_HOST,
port: +process.env.DB_PORT,
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
synchronize: process.env.NODE_ENV !== 'prod',
logging: process.env.NODE_ENV !== 'prod',
entities: [Users,Gs],
}),
여기까지 NestJs 작업을 마치고 실행시켜준다.
$ npm run start:dev
이제 CSV 파일을 import 시켜주어야한다.
pgadmin4 를 이용하면 쉽게 import 할 수 있다.
주의해야하는 점은 import column 에서 id 는 빼주어야 한다. (id 는 PK 이므로)
데이터가 잘 들어와있으면 graphql 을 확인해준다.
localhost/xxxx/graphql에 접속한다.
이로써 주식데이터를 localhost상에서 확인 가능하게 되었다.
다음으로는 React와 연동을 시켜 그래프를 만들 예정이다.
'개발팁저장소 > nestjs' 카테고리의 다른 글
[Nextjs] 주식사이트 만들기-5 채팅 프론트엔드 백엔드(Apollo client, graphQL, Nextjs, NestJs, Websocket) (0) | 2021.12.13 |
---|---|
[NestJS]Websocket & Subscription 문제가 풀리지 않는다. (0) | 2021.12.10 |
[Nestjs] 주식사이트 만들기-2 채팅 백엔드 만들기 (GraphQL & Apollo) (0) | 2021.12.10 |
[Nestjs] 주식사이트 만들기-2 채팅 백엔드 만들기 (WebSoketGateway with NestJS) (0) | 2021.12.09 |