묻고 답해요
130만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨따라하며 배우는 NestJS
delete({ id, user}) 안되는 문제
저는 id => { id, user} 로 변경하니 type 에러가 발생했습니다.그래서(mac기준) 커맨드 + delete 함수 클릭criteria 변수에 { id:number, user:User} 타입 추가저장이 방법으로 해결했습니다.별거 아니지만 저는 엄청 헤매서 공유차 남깁니다..!
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
스웨거 문서를 PickType으로 만들 수 있나요?
1. Users.ts(엔티티) import { Column, CreateDateColumn, DeleteDateColumn, Entity, Index, JoinTable, ManyToMany, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn, } from 'typeorm'; import { ChannelChats } from './ChannelChats'; import { ChannelMembers } from './ChannelMembers'; import { Channels } from './Channels'; import { DMs } from './DMs'; import { Mentions } from './Mentions'; import { WorkspaceMembers } from './WorkspaceMembers'; import { Workspaces } from './Workspaces'; import { IsEmail, IsNotEmpty, IsString } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; @Index('email', ['email'], { unique: true }) @Entity({ schema: 'sleact', name: 'users' }) export class Users { @PrimaryGeneratedColumn({ type: 'int', name: 'id' }) id: number; @ApiProperty({ example: `aaa123@google.com`, description: '이메일', required: true, }) @IsEmail() @IsNotEmpty() @Column('varchar', { name: 'email', unique: true, length: 30 }) email: string; @ApiProperty({ example: `홍길동`, description: '닉네임', required: true, }) @IsString() @IsNotEmpty() @Column('varchar', { name: 'nickname', length: 30 }) nickname: string; @ApiProperty({ example: `123123`, description: '비밀번호', required: true, }) @IsString() @IsNotEmpty() @Column('varchar', { name: 'password', length: 100, select: false }) password: string; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; @DeleteDateColumn() deletedAt: Date | null; @OneToMany(() => ChannelChats, (channelchats) => channelchats.User) ChannelChats: ChannelChats[]; @OneToMany(() => ChannelMembers, (channelmembers) => channelmembers.User) ChannelMembers: ChannelMembers[]; @OneToMany(() => DMs, (dms) => dms.Sender) DMs: DMs[]; @OneToMany(() => DMs, (dms) => dms.Receiver) DMs2: DMs[]; @OneToMany(() => Mentions, (mentions) => mentions.Sender) Mentions: Mentions[]; @OneToMany(() => Mentions, (mentions) => mentions.Receiver) Mentions2: Mentions[]; @OneToMany( () => WorkspaceMembers, (workspacemembers) => workspacemembers.User, ) WorkspaceMembers: WorkspaceMembers[]; @OneToMany(() => Workspaces, (workspaces) => workspaces.Owner) OwnedWorkspaces: Workspaces[]; @ManyToMany(() => Workspaces, (workspaces) => workspaces.Members) @JoinTable({ name: 'workspacemembers', joinColumn: { name: 'UserId', referencedColumnName: 'id', }, inverseJoinColumn: { name: 'WorkspaceId', referencedColumnName: 'id', }, }) Workspaces: Workspaces[]; @ManyToMany(() => Channels, (channels) => channels.Members) @JoinTable({ name: 'channelmembers', joinColumn: { name: 'UserId', referencedColumnName: 'id', }, inverseJoinColumn: { name: 'ChannelId', referencedColumnName: 'id', }, }) Channels: Channels[]; } 2. join.request.dto import { PickType } from '@nestjs/mapped-types'; import { Users } from '../../entities/Users'; export class JoinRequestDto extends PickType(Users, [ 'email', 'nickname', 'password', ] as const) {} 3. user.dto import { JoinRequestDto } from './join.request.dto'; import { ApiProperty } from '@nestjs/swagger'; export class UserDto extends JoinRequestDto { @ApiProperty({ example: `1`, description: '아이디', required: true, }) id: number; } 4. users.controller import { Body, Controller, ForbiddenException, Get, NotFoundException, Post, Req, Res, UseGuards, UseInterceptors, } from '@nestjs/common'; import { UsersService } from './users.service'; import { JoinRequestDto } from './dto/join.request.dto'; import { User } from '../common/decorators/user.decorator'; import { UndefinedToNullInterceptor } from '../common/interceptors/undefinedToNull.interceptor'; import { LocalAuthGuard } from '../auth/local-auth.guard'; import { NotLoggedInGuard } from '../auth/not-logged-in.guard'; import { LoggedInGuard } from '../auth/logged-in.guard'; import { ApiCookieAuth, ApiOperation, ApiResponse, ApiTags, } from '@nestjs/swagger'; import { Users } from '../entities/Users'; import { UserDto } from './dto/user.dto'; @ApiTags('USERS') @UseInterceptors(UndefinedToNullInterceptor) @Controller('api/users') export class UsersController { constructor(private readonly usersService: UsersService) {} @ApiCookieAuth('connect.sid') @ApiOperation({ summary: '내 정보 가져오기' }) @ApiResponse({ type: UserDto, }) @Get() async getMyProfile(@User() user: Users) { return user || false; } @ApiResponse({ status: 500, description: 'Server Error..', }) @ApiResponse({ status: 200, description: '성공!', }) @ApiOperation({ summary: '회원가입' }) @UseGuards(NotLoggedInGuard) @Post() async join(@Body() body: JoinRequestDto) { const user = this.usersService.findByEmail(body.email); if (!user) { throw new NotFoundException(); } const result = await this.usersService.join( body.email, body.nickname, body.password, ); if (result) { return 'ok'; } else { throw new ForbiddenException(); } } @ApiResponse({ status: 200, description: '성공', type: UserDto, }) @ApiOperation({ summary: '로그인' }) @UseGuards(LocalAuthGuard) @Post('login') async login(@User() user: Users) { return user; } @ApiCookieAuth('connect.sid') @ApiOperation({ summary: '로그아웃' }) @UseGuards(LoggedInGuard) @Post('logout') async logout(@Req() req, @Res() res) { req.logOut(); res.clearCookie('connect.sid', { httpOnly: true }); res.send('ok'); } } ---------------------------- 스웨거 문서 1. Dto 관련 스키마 2. usersDto를 사용한 결과 3. joinRequestDto를 사용한 결과 마지막 결과 쪽에 제가 생각한 것은 빈칸이 아니라{ email : "aaa123@google.com" nickname: "홍길동" passwork: "123123"} 이었는데 빈칸으로 나오네요.. 혹시 잘못한 부분이 있을까요?
-
미해결따라하며 배우는 NestJS
EntityRepository 가 deprecated 됐다고 나옵니다.
캡처한것처럼 deprecate됐다고 나오는데 그냥 이후 수업 진행해도 되는건가요?
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
제로초님 질문드리고싶습니다. 이런문제는 왜발생한건지 파일 캡쳐합니다 도저히 이해가 안돼네요 undefined property verify
import { Injectable, ExecutionContext, HttpException, HttpStatus, } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { JwtService } from '@nestjs/jwt'; @Injectable() export class JwtAuthGuard extends AuthGuard('jwt') { constructor( private readonly jwtService: JwtService, // @Inject(forwardRef(() => AdminsService)) // private readonly adminsService: AdminsService, ) { super(); } canActivate(context: ExecutionContext) { const request = context.switchToHttp().getRequest(); const { authorization } = request.headers; if (authorization === undefined) { throw new HttpException('Token 전송 안됨', HttpStatus.UNAUTHORIZED); } //const token = authorization.replace('Bearer ', authorization); const token = authorization.replace('Bearer ', ''); //console.log(token, 'token!!!'); request.user = this.validateToken(token); return true; } validateToken(token: string) { const secretKey = process.env.SECRET ? process.env.SECRET : 'dev'; try { const data = this.jwtService.verify(token, { secret: secretKey, }); console.log(data, '11번가데이터'); return data; } catch (e) { switch (e.message) { // 토큰에 대한 오류를 판단합니다. case 'INVALID_TOKEN': case 'TOKEN_IS_ARRAY': case 'NO_USER': throw new HttpException('유효하지 않은 토큰입니다.', 401); case 'EXPIRED_TOKEN': throw new HttpException('토큰이 만료되었습니다.', 410); default: console.trace(e); // console.log('광섭짱과 함께하는 코딩공부',) throw new HttpException('서버 오류입니다.', 500); } } } } 이부분은 jwt.guard.ts 입니다 저 빨간줄에서 Trace: TypeError: Cannot read properties of undefined (reading 'verify') 이렇게 나오는데 왜 저렇게 나오는건지 도저히 모르겠네요 해당 토큰값도 잘 받아와서 verify 를 이용해 토큰 유효성 검사를 진행하려하는데 그부분에서 에러가 계속 납니다... 도와주세요
-
미해결따라하며 배우는 NestJS
ERROR [ExceptionHandler] No repository for "BoardRepository" was found.
안녕하세요. 데이터베이스를 이용한 CRUD 구현 > 게시물 생성하기 를 들으면서 service와 controller 코드를 고치고 npm run start:dev 실행을 하니 아래와 같은 오류가 뜹니다. 똑같이 코드를 보며 하고있는데 아래와 같은 오류가 뜨는 이유를 알 수 있을까요?? ERROR [ExceptionHandler] No repository for "BoardRepository" was found. Looks like this entity is not registered in current "default" connection? RepositoryNotFoundError: No repository for "BoardRepository" was found. Looks like this entity is not registered in current "default" connection? at RepositoryNotFoundError.TypeORMError [as constructor] (/Users/Desktop/nestjs_crud/src/error/TypeORMError.ts:7:9) at new RepositoryNotFoundError (/Users/Desktop/nestjs_crud/src/error/RepositoryNotFoundError.ts:10:9) at EntityManager.getRepository (/Users/Desktop/nestjs_crud/src/entity-manager/EntityManager.ts:964:19)
-
미해결탄탄한 백엔드 NestJS, 기초부터 심화까지
common entity 상속 시 컬럼 순서 문제
안녕하세요 typeorm 강의에서 쓰신 common entity를 상속하는 코드를 사용하면 위와 같이 컬럼 순서가 나오는데 이렇게 되면 가독성이 안좋아서 컬럼 순서를 바꿔보려 했습니다. 검색해보니 엔티티를 상속했을때 컬럼 순서를 바꿀수 없다고 합니다. https://www.mrlatte.net/code/2020/11/03/typeorm-entity-inheritance.html 실무에서는 어떻게 사용하시는지 궁금합니다.
-
미해결따라하며 배우는 NestJS
BoardsController 못불러와요 ㅜ_ㅜ
안녕하세요, controller까지 작성하고 npm run start:dev로 테스트시 빈배열을 못불러오고 {"statusCode":404,"message":"Cannot GET /boards","error":"Not Found"} 통신이 안되네요 ㅜ_ㅜ 터미널을 보니, 모듈까지 불러오고 컨트롤러는 못불러옵니다ㅜㅜ MAPPED{/borads, GET} route도 못불러오구요.. 그냥 모듈까지 불러오고 스타트가 되는데 어떻게 해야할까요 ㅜㅜ?
-
미해결탄탄한 백엔드 NestJS, 기초부터 심화까지
TypeORM + Mysql관련 질문
NestJS + TypeOrm을 통해서 데이터베이스(mysql)에 데이터를 Insert하는데 있어 질문 드립니다 (구글링을 해보았지만 TypeOrm의 업데이트가 되서 안먹히는건지, 제가 방법을 잘못활용하고 있는건지 모르겠습니다 / 공식문서대로 해봐도 안되네요 ㅜㅠ) 하고자 하는것 데이터 Insert시 CreatedAt과 UpdatedAt을 자동적으로 같이 입력되도록 하는것 문제점 둘다 null값으로 입력됨 3. 파일 group.ts -> typeorm의 entity파일 @Entity 데코레이터로 정의 4. 시도해본 것 공식문서 @CreateDataColumn() => null로 나옴 @CreateDataColumn({default() => CURRENT_TIMESTAMP(6)}) @Column({{default() => CURRENT_TIMESTAMP(6)}) => null로 나옴 default: Date.now() => null로 나옴 createdAt의 타입문제인가싶어 타입도 any로 해서 진행해봄 아래는 필요한 소스코드 일부를 발췌했습니다 ================= import { BaseEntity, Column, CreateDateColumn, Entity, Index, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn, } from 'typeorm'; import { Appliers } from './Appliers'; import { Comments } from './Comments'; import { Users } from './Users'; @Index('FK_Users_TO_Groups_1', ['userId'], {}) @Entity('Groups', { schema: 'erunjrun' }) export class Groups extends BaseEntity { @CreateDateColumn() createdAt: any; }
-
미해결따라하며 배우는 NestJS
findOne(id) 에서 에러가 발생한 경우 해결법
# Info 강의 업로드 연도(2021) 와 수강 연도(2022) 사이에 TypeORM 의 버전이 달라서, Repository.findOne() 메서드의 구성이 달라진 것 같다고 생각합니다.강의 대로 코드를 작성하면 후술할 에러가 발생하는데, 해당 부분을 해결하고 나서, 다른 수강생 분들 도 이런 문제를 겪을까 생각되어서 따로 글로 남기게 되었습니다. ## 문제 세 줄 요약 1. fineOne( id) 를 하면 에러가 발생 2. 관련 레퍼런스가 없어서 TypeORM docs 확인 3. fineOneBy({id}) 로 에러 해결 (2022-03-30) 자세한 내용은 ### 해결방법, ### 참고문서, ### 초기질문 참고해주세요.깃 : unchaptered/22-03-nestjs-board: Nest.JS (github.com) ### 해결방법 2022년 3월 30일 기준으로, this.boardsRepository.findOne( id ); 위와 같이 입력을 했는데 에러가 발생했다면, 해당 부분을 다음의 코드로 교체해서 해결할 수 있습니다. this.boardsRepository.fineOneBy({ id }); ### 참고문서 아래 페이지에서 Ctrl + F 로 fineOne 혹은 fineOneBy 를 검색해서 확인하시면 됩니다.TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms. ### 초기 질문 boards.service.ts 의 getBoardById() 에서 this.boardsRepository.fineOne(id); 를 하면 id 에 붉은 경고가 다음과 같이 발생하고 있습니다. 혹시 해당 부분이 왜 문제가 되는지 알 수 있을까요? 정크 데이터까지만 푸쉬 해놓았지만, node_module 버전 문제일까 싶어서 깃 허브 링크도 최하단에 올려놓겠습니다. 위의 에러가 발생하는 해당 코드입니다. async getBoardById(id: number): Promise<Board> { const found = await this.boardsRepository.findOne(id); if (!found) throw new NotFoundException(`Can't find Board by ${id}`); return found; } 엔티티 import { BaseEntity, Column, PrimaryColumn, PrimaryGeneratedColumn } from "typeorm"; import { BoardStatus } from "./board-status.enum"; export class Board extends BaseEntity { @PrimaryGeneratedColumn() id: number; @Column() title: string; @Column() description: string; @Column() status: BoardStatus; } baords.repository.ts import { EntityRepository, Repository } from "typeorm"; import { Board } from "./entity/board.entity"; @EntityRepository(Board) export class BoardsRepository extends Repository<Board> { } 깃허브 : unchaptered/22-03-nestjs-board: Nest.JS (github.com)
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
하나의 게시물에 여러 개의 태그(카테고리)를 조회하고 싶습니다
현재 nestjs로 Stackoverflow와 유사한 교내 웹 개발 커뮤니티를 개발하는 학생입니다. 전체 질문글을 조회하는 기능을 개발하다가 한 가지 궁금점이 발생하여 질문하게 되었는데요! 주제넘게 설명을 드리자면 '전체 질문글 조회'는 velog나 stackoverflow와 같은 사이트의 루트페이지를 생각해주시면 될 것같습니다. 모든 질문글을 조회하는 과정에서 하나의 질문글에 여러 개의 카테고리가 저장되어 있을 경우 해당 질문글에 연관 돼있는 카테고리가 배열에 담겨 반환되는 것이 아닌 같은 질문글에 다른 카테고리를 가진 똑같은 질문글들이 조회됩니다. 즉, 다시 말해 질문글은 같지만 카테고리만 다른 데이터가 카테고리의 갯수만큼 조회됩니다..!! 이건 저희 프로젝트 erd입니다. 다음은 같이 querybuilder를 이용하여 left join을 한 코드입니다. 아래 사진은 위 querybuilder를 통해 도출된 결과입니다 위의 내용은 전체 조회에서 필요한 하나의 질문글에 대한 정보들은 조회한 사진입니다. 제가 원하는 출력 결과는 위의 카테고리가 따로 조회되는 것이 아닌 ```typescript TextRow { username: '송유현', '댓글내용': '댓글1', '제목': 'typeorm이 뭐에요', '내용': '제곧내', '좋아요': 3, '생성시간': 2021-12-21T15:00:00.000Z, '태그': [ [ '킥킥'] , ['typeorm'] ] }, ``` 의 형태로 출력하고 싶습니다..
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
제로초님 nestjs vscode에서 디버깅하는 것 좀 알려주시면 감사합니다.
안녕하세요 제로초님. 강의 잘 봤습니다. 그런데 제가 vscode에서 nestjs 프로젝트를 하면서 브레이킹 포인트로 디버깅을 하고 싶은데 브레이킹 포인트가 안 먹혀서 질문드립니다. 인터넷에서 보고 launch.json 파일도 만들어서 해봤는데 계속 타입스크립트로 디버깅이 안되더라고요. 방법을 알려주시면 감사하겠습니다.
-
미해결따라하며 배우는 NestJS
Dependency Injection에 관해
안녕하세요 선생님, 항상 좋은 강의 감사드립니다. DI 관련해서 궁금한 점이 생겨 질문드립니다. Controller에서 Service 클래스를 DI 받을 때는 별도의 데코레이션 없이 DI를 받았는데, service 계층에서 repository를 DI 받을 때는 왜 @InjectRepository가 필요할까요? 개인적으로 생각해보기로는, 우리가 직접 만든 Service 클래스는 Nest IOC container에서 관리되지만, Repository 클래스는 TypeORM 모듈에 의해 DI가 관리되기 때문일 수도 있겠다는 생각을 해봤습니다.
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
1분 18초 자바스크립트 어떤건 힙에 저장되고 어떤건 스택에 저장되고...
1분 18초 자바스크립트 어떤건 힙에 저장되고 어떤건 스택에 저장되고... 에 대해 말씀하셨는데, 혹시 그런거에 관해 좀 더 알기 위해 공부해보고 싶은데, 공부 자료 추천해주실 수 있나요? (신기... 제로초님은 어떤 자료를 통해 그러한 내용들을 알게되셨나요?
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
React Nodebird때 만들었던 Follow기능(=many to many)질문 입니다 (Sequelize vs Typeorm)
안녕하세요? 제로초님 노드버드 강의를 완강하고, 어느새 sleact 강좌도 마무리 시점이 와가네요. 항상 감사합니다 이번 typeorm관계설정 강의를 듣다가 궁금한점이 생겼는데 도저히 해결이 되지않아 이렇게 질문을 드립니다. 노드버드 강좌에서 팔로워/팔로이 기능을 model에서 정의할때 Sequelize로 아래와 같이 belongsToMany에 as 와 through를 이용해서 설정했었는데요, // 관계 설정 User.associate = (db) => { ... db.User.belongsToMany(db.User, { through: 'Follow', as: 'Followers', foreignKey: 'followingId' }); db.User.belongsToMany(db.User, { through: 'Follow', as: 'Followings', foreignKey: 'followerId' }); // 같은 테이블에서 다대다 관계일때는 foreignKey넣어주어야 됨 // WHY? : 자바스크립트 객체에서 구별하는 이름이 as이고, DB에서는 foreignKey를 이용해 구별한다. }; Typeorm에서 이와같이 user대user 관계에서 팔로우 기능을 구현해보려고 스스로 학습중인데, 검색해도 나오지를 않고 어떻게 해야할지 감이 안잡히네요... Typeorm에는 Sequelize처럼 이렇게 편리한 기능이 없는것인거겠죠? ㅠ 만약 Typeorm에서 제공하는 as 나 Through기능이 없다면, Typeorm에서는 노드버드에서와 같은 팔로워/팔로이 기능을 어떻게 구현해야할지 궁금합니다!
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
save()로 저장하고 id값을 리턴받아서 update를 하고 싶습니다.
안녕하세요 nest+typeORM으로 공부를 하고 있습니다. 특정 테이블에 save()로 저장을 하고 리턴값으로 id값을 받아와서 특정 필드에 저장을 할 수 있는 방법이 있을까요? 이렇게 할려면 따로따로 구현을 해야하는지 아니면 한번에 구현을 할 수 있는 방법이 있는지 궁금합니다.
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
질문있습니다!
typeorm에서 nullable: false로 지정하면 db에 저장될때 값이 없으면 에러를 띄울수있고 class-validator에서 @IsNotEmpty를 사용하면 PickType을 사용해 엔티티를 상속받은 Dto단에서 값이 없을때 에러를 띄울수 있는데 어떤쪽에서 에러처리하는게 더 효율적일까요?
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
TypeORM 반환 데이터 구조
아래와 같이 조인했을 시에 조인 결과가 배열안에 객체로 나오는데 sequelize처럼 여러 객체로 결과 반환할 수 있는 방법이 있을까요? 혹시 몰라서 OneToOne으로 관계 설정 맺었는데 맞는 방법일까요: [ { "id": 30, "equipmentName": "수도(용수) 유량계", "locationMainId": 1, "locationSubId": 3, "importance": null, "energyId": 30, "installDtm": null, "serialNum": null, "energyPurposeName": "급탕", "name": "여자화장실 온수기수도계량기", "remark": null, "created": "2021-05-20T00:52:11.000Z", "updated": "2021-06-15T00:44:36.000Z", "x": 100, "y": 100, "webaccessTags": [ { "tagname": "T3_PT1_Freq*01M", "equipmentMgmtId": 30, "tagDescription": "temperature", "unit": null, "unitConversion": { "type": "Buffer", "data": [0] }, "isTrend": { "type": "Buffer", "data": [0] }, "loggingTime": 300, "energyType": null } ] }, { "id": 54, "equipmentName": "습도 계측기", "locationMainId": 1, "locationSubId": 2, "importance": null, "energyId": null, "installDtm": null, "serialNum": null, "energyPurposeName": null, "name": "복도습도", "remark": null, "created": "2021-05-20T01:12:12.000Z", "updated": "2021-06-14T09:02:02.000Z", "x": 0, "y": 0, "webaccessTags": [ { "tagname": "T3_PT1_Humidity*01M", "equipmentMgmtId": 54, "tagDescription": "123", "unit": null, "unitConversion": { "type": "Buffer", "data": [0] }, "isTrend": { "type": "Buffer", "data": [0] }, "loggingTime": 60, "energyType": "습도계" } ] }, { "id": 53, "equipmentName": "온도 계측기", "locationMainId": 1, "locationSubId": 2, "importance": null, "energyId": null, "installDtm": null, "serialNum": null, "energyPurposeName": null, "name": "복도온도", "remark": null, "created": "2021-05-20T01:11:58.000Z", "updated": "2021-06-14T09:02:03.000Z", "x": 0, "y": 0, "webaccessTags": [ { "tagname": "T3_PT1_Temp*01M", "equipmentMgmtId": 53, "tagDescription": "123", "unit": null, "unitConversion": { "type": "Buffer", "data": [0] }, "isTrend": { "type": "Buffer", "data": [0] }, "loggingTime": 60, "energyType": "온도계" } ] }]