728x90
반응형

TypeORM에 관해 공부하다가 공식홈페이지를 방문하게 되었다.

다른 블로그 글보다 훨씬 깔끔하게 적혀있으며 이해하기 쉬웠다.

가능하면 공식홈페이지에서 보는 것을 추천한다.

다만 나는 내가 필요한 부분만 골라서 요약정리할 생각이다.

 

공식홈페이지 https://typeorm.io/

 

TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server,

 

typeorm.io

 

단계별 가이드

 

# 모델 생성

데이터베이스 작업은 테이블 생성에서 시작됩니다. TypeORM에게 데이터베이스 테이블을 생성하도록

어떻게 지시합니까? 답은 모델을 통해서입니다. 앱의 모델은 데이터베이스 테이블입니다.

export class Photo {
    id: number
    name: string
    description: string
    filename: string
    views: number
    isPublished: boolean
}

그리고 데이터베이스에 사진을 저장하려고 합니다. 데이터베이스에 물건을 저장하려면

먼저 데이터베이스 테이블이 필요하고 모델에서 데이터베이스 테이블이 생성됩니다. 

모든 모델이 아니라 엔티티 로 정의한 모델만 해당됩니다 .

 

# 엔티티 생성

엔티티데코레이터 가 장식한 모델입니다. 이러한 모델에 대한 데이터베이스 테이블이 생성됩니다. 

TypeORM의 모든 곳에서 엔티티로 작업합니다. 로드/삽입/업데이트/제거하고 다른 작업을 수행할 수 있습니다.

import { Entity } from "typeorm"

@Entity()
export class Photo {
    id: number
    name: string
    description: string
    filename: string
    views: number
    isPublished: boolean
}

우리는 데이터베이스 테이블을 생성했지만 열 없이 존재할 수 있는 테이블은 무엇입니까? 

데이터베이스 테이블에 몇 개의 열을 만들어 보겠습니다.

 

# 테이블 열 추가 (최종)

데이터베이스 열을 추가하려면 데코레이터를 사용하여 열로 만들려는 엔터티의 속성을 장식하기만 하면 됩니다

import { Entity, Column, PrimaryGeneratedColumn } from "typeorm"

@Entity()
export class Photo {
    @PrimaryGeneratedColumn()
    id: number

    @Column({
        length: 100,
    })
    name: string

    @Column("text")
    description: string

    @Column()
    filename: string

    @Column("double")
    views: number

    @Column()
    isPublished: boolean
}

 

# 기본메소드

find(): 주어진 조건에 맞는 데이터를 조회하는 메소드입니다. 조회 결과는 배열 형태로 반환됩니다.

findOneBy(): 주어진 조건에 맞는 데이터 중 첫 번째 데이터를 조회하는 메소드입니다. 
             조회 결과는 객체 형태로 반환됩니다.

findAndCount(): 주어진 조건에 맞는 데이터를 조회하고, 
해당 데이터의 총 개수를 반환하는 메소드입니다. 조회 결과는 배열 형태로 반환됩니다.

save(): 새로운 데이터를 추가하거나, 기존 데이터를 수정하는 메소드입니다. 
만약 주어진 데이터가 이미 존재한다면 수정되고, 존재하지 않는다면 새로 추가됩니다.

remove(): 주어진 조건에 맞는 데이터를 삭제하는 메소드입니다.

updateOne(): 주어진 조건에 맞는 첫 번째 문서를 수정하는 메소드입니다.

updateMany(): 주어진 조건에 맞는 모든 문서를 수정하는 메소드입니다.

countDocuments(): 주어진 조건에 맞는 문서의 개수를 반환하는 메소드입니다.

distinct(): 주어진 필드에 대해 중복을 제거한 유일한 값을 반환하는 메소드입니다.

aggregate(): 복잡한 데이터 처리를 위한 파이프라인을 생성하여 데이터를 조회하는 메소드입니다.

populate(): 다른 컬렉션에 있는 데이터를 참조하고 있는 필드의 값을 해당 컬렉션의 데이터로 채우는 메소드입니다.

sort(): 조회 결과를 정렬하는 메소드입니다.

limit(): 조회 결과를 제한하는 메소드입니다.

skip(): 조회 결과에서 일부 데이터를 제외하는 메소드입니다.

 

# 일대일 관계 만들기

우리는 또한 @JoinColumn데코레이터를 추가하여 관계의 이 쪽이 관계를 소유할 것임을 나타냅니다. 

관계는 단방향 또는 양방향일 수 있습니다. 관계형의 한쪽만 소유할 수 있습니다. 

데코레이터를 사용하는 @JoinColumn은 관계의 소유자 측에서 필요합니다.

@Entity()
export class PhotoMetadata {
    /* ... other columns */
    @OneToOne(() => Photo)
    @JoinColumn()
    photo: Photo
}

# 관계의 반대면

관계는 단방향 또는 양방향일 수 있습니다. 현재 PhotoMetadata와 Photo 간의 관계는 단방향입니다. 

관계의 소유자는 PhotoMetadata이고 Photo는 PhotoMetadata에 대해 아무것도 모릅니다. 

이로 인해 사진 쪽에서 PhotoMetadata에 액세스하기가 복잡해집니다.

이 문제를 해결하려면 역 관계를 추가하고 PhotoMetadata와 Photo 간의 관계를 양방향으로 만들어야 합니다. 

@Entity()
export class PhotoMetadata {
    /* ... other columns */

    @OneToOne(() => Photo, (photo) => photo.metadata)
    @JoinColumn()
    photo: Photo
}
@Entity()
export class Photo {
    /* ... other columns */

    @OneToOne(() => PhotoMetadata, (photoMetadata) => photoMetadata.photo)
    metadata: PhotoMetadata
}

 

# 다른 표기법(GPT 문의결과)

    @OneToOne(() => PhotoMetadata, (photoMetadata) => photoMetadata.photo)
    metadata: PhotoMetadata

    @OneToOne(() => PhotoMetadata, (photoMetadata) => photoMetadata.photo)
    metadata: Relation<PhotoMetadata>

결론은 두번째 코드를 사용하는 것이 좋아보인다.

더보기

첫 번째 코드에서는 metadata 속성이 PhotoMetadata 객체를 직접 참조하고 있습니다.

반면 두 번째 코드에서는 metadata 속성의 타입이 Relation<PhotoMetadata>으로 정의되어 있습니다.

 

이 차이점은 타입스크립트 타입과 ORM의 동작 방식과 관련이 있습니다.

첫 번째 코드에서는 metadata 속성이 PhotoMetadata 객체를 직접 참조하므로,

해당 속성을 사용하여 Photo 객체를 로드하면 PhotoMetadata 객체가 자동으로 연결됩니다.

 

반면 두 번째 코드에서는 metadata 속성의 타입이 Relation<PhotoMetadata>으로 정의되어 있으므로,

해당 속성을 사용하여 Photo 객체를 로드하더라도 PhotoMetadata 객체는 자동으로 연결되지 않습니다.

대신, 해당 속성을 사용하여 PhotoMetadata 객체를 직접 로드해야 합니다.

 

따라서 두 번째 코드에서는 metadata 속성을 사용하여 PhotoMetadata 객체를 로드하기 전에 Relation<PhotoMetadata> 타입으로 선언된 속성을 사용하여 필요한 쿼리를 생성하고,

이를 실행하여 PhotoMetadata 객체를 로드해야 합니다. 이 방식은 ORM의 성능을 최적화하고,

불필요한 데이터를 로드하지 않도록 도와줍니다.

 

# 관계와 함께 객체 로드하기

객체로드 하는 방법을 두가지가 있다. 차이점은 간단하게 할거냐, 상세하게 할거냐이므로 선택인듯 하다.

 

첫번째, TypeORM Repository Query 

const photos = await photoRepository.find({
    relations: {
        metadata: true,
    },
})

두번째, TypeORM Query builder

const photos = await AppDataSource.getRepository(Photo)
    .createQueryBuilder("photo")
    .innerJoinAndSelect("photo.metadata", "metadata")
    .getMany()

 

# 캐스케이드를 사용하여 관련 객체를 자동으로 저장

다른 개체가 저장될 때마다 관련 개체를 저장하려는 경우 관계에서 캐스케이드 옵션을 설정할 수 있습니다.

export class Photo {
    // ... other columns

    @OneToOne(() => PhotoMetadata, (metadata) => metadata.photo, {
        cascade: true,
    })
    metadata: PhotoMetadata
}

cascade옵션에 대한 설명

더보기

cascade 옵션은 관계형 데이터베이스에서 엔티티를 저장, 업데이트, 삭제할 때

연관된 엔티티의 동작을 제어하는 옵션입니다.

엔티티가 저장, 업데이트, 삭제될 때 관련된 PhotoMetadata 엔티티도 함께 저장, 업데이트, 삭제됩니다.

cascade 옵션은 일대일, 일대다, 다대일, 다대다 관계 모두에서 사용할 수 있습니다.

cascade 옵션은 아래와 같은 값들을 가질 수 있습니다.

  • remove: 해당 엔티티가 삭제될 때 연관된 엔티티도 함께 삭제됩니다.
  • save: 해당 엔티티가 저장될 때 연관된 엔티티도 함께 저장됩니다.
  • update: 해당 엔티티가 업데이트될 때 연관된 엔티티도 함께 업데이트됩니다.
  • soft-remove: 해당 엔티티가 삭제될 때 연관된 엔티티도 삭제 대신 삭제 플래그를 설정합니다.
  • recover: 해당 엔티티가 복원될 때 연관된 엔티티도 함께 복원됩니다.

cascade 옵션은 데이터베이스 작업을 간편하게 해주지만, 관련된 모든 엔티티가 동일한 작업을 수행하기 때문에 주의해서 사용해야 합니다. 특히 대규모 애플리케이션에서는 적절한 cascade 옵션을 설정하는 것이 성능 및 데이터 무결성 관리에 중요합니다.

 

# 다대일/일대다 관계생성

@Entity()
export class Author {
    @OneToMany(() => Photo, (photo) => photo.author) 
    //참고: 아래 Photo 클래스에 작성자 속성을 생성합니다.
    photos: Photo[]
}
@Entity()
export class Photo {
    @ManyToOne(() => Author, (author) => author.photos)
    author: Author
}

 

# 다대다 관계생성

@Entity()
export class Album {
    @ManyToMany(() => Photo, (photo) => photo.albums)
    @JoinTable()
    photos: Photo[]
}
export class Photo {
    @ManyToMany(() => Album, (album) => album.photos)
    albums: Album[]
}

애플리케이션을 실행한 후 ORM은 album_photos_photo_albums 접합 테이블을 생성합니다 .

 

AlbumORM에서 연결에 클래스를 등록하는 것을 잊지 마십시오 .

 

이제 데이터베이스에 앨범과 사진을 삽입해 보겠습니다.

import { AppDataSource } from "./index"

// create a few albums
const album1 = new Album()
album1.name = "Bears"
await AppDataSource.manager.save(album1)

const album2 = new Album()
album2.name = "Me"
await AppDataSource.manager.save(album2)

// create a few photos
const photo = new Photo()
photo.name = "Me and Bears"
photo.description = "I am near polar bears"
photo.filename = "photo-with-bears.jpg"
photo.views = 1
photo.isPublished = true
photo.albums = [album1, album2]
await AppDataSource.manager.save(photo)

// now our photo is saved and albums are attached to it
// now lets load them:
const loadedPhoto = await AppDataSource.getRepository(Photo).findOne({
    where: {
        id: 1,
    },
    relations: {
        albums: true,
    },
})

 

 

 

 

 

 

728x90
반응형
728x90
반응형

소켓기능을 포기하고,

북마크 기능을 담당하게 되었다. 기본적인 CRUD이며, 꼭 필요한 기능이다.

 

기본적인 CRUD는 같은 조원의 코드를 참고하고,

데이터연결은 이전에 들었던 강의를 다시 들으며 복습하여 코드를 완성했다.

 

그런데 현재 ERD관계가 처음 작성했을때의 모습과 달라서

엔티티를 다시 수정중이다.

 

리더님이 작성해주신다하여 나는 TypeORM에 대해서 공부중이다.

https://typeorm.io/

 

TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server,

 

typeorm.io

공식홈페이지가 예시가 풍부하고 이해하기 쉽다.

해당 홈페이지를 참고해서 개념 정리해야겠다.

728x90
반응형
728x90
반응형

월요일, 화요일 2일간 코딩하면서 괴로웠다.

소켓의 기본 껍데기를 만드는건 쉬웠지만,

DB와 연동하여 데이터를 저장하고 불러오는 것이 어려웠다.

 

소켓에 대한 지식과 개념이 부족해서

전체적인 흐름을 잡기가 어려웠다.

 

결국 튜터님에게 상의받았으나

답변을 듣고도 진행이 어려울 것 같아서 팀원들에게

프로젝트에서 소켓 사용은 어려울 것 같다고 얘기했다.

 

첫번째 이유, 소켓을 사용하는 사람이 없어서 다른 동기 및 튜터님들의 도움 받기가 어렵다.

두번째 이유, 취업할때 소켓경험을 보는 곳이 얼마 없을 것이다. 작은 기업일수록 채팅은 개발하기 보단 API를 끌고 올듯.

세번쨰 이유, 나의 실력부족.

 

팀원들에게 미안하다고 얘기했고, 쪽지만들기로 가야되나 했다가

남아있는 기능 북마크로 가는건 어떠냐해서 북마크를 만들기로 했다.

기본적인 CRUD만드는 경험이 될 것 같고

모르더라도 물어보기가 소켓보다는 훨씬 쉬워질 것 같아서 마음이 편해졌다.

일주일 지나서 갑자기 포기하게 되었지만 더 늦어지면 차질이 생길 것 같았고

이 사실을 흔쾌히 받아준 팀원들에게 고마운 마음 뿐이다.

728x90
반응형
728x90
반응형

1. 문제

더보기

ERROR [WsExcepionsHandler] Chatting validation failed: nickname: 

Cast to Embedded failed for value "닉네임" (type string)

at path "nickname" because of "ObjectExpectedError"

오늘 2번이나 나를 괴롭게 했던 에러문구! (더보기 클릭)

몽구스 model 관련 에러였다.

 

2. 시도해본 것들

오늘은 채팅하면서 닉네임과 채팅내용을 가져오는 작업을 했다.

강의를 보면서 코드를 완성했다.

그런데 채팅메시지가 null로 들어가서

이것저것 손보다가 에러 문구를 봤다. 

 

[validation failed]

 

검색해보면서 model관련 에러인것을 알았고,

유효성 실패?? 대충 단어를 보고 어디에 문제가 있는지 떠올려야 했다.

메시지의 경우는 model에선 chat이라 쓰고, gateway에선 message라고 쓰는 등

중구난방으로 사용했길래 통일해서 해결완료.

 

닉네임 값도 저장하고 싶은데 계속 null이 뜨거나

다음과 같이 에러문구가 발생했다.

 

3. 해결과정

    await this.chattingModel.create({
      nickname: client.data.nickname,
      message,
    });

 위의 코드를 계속 수정해가며 테스트했다.

nickname : socketObj

nickname : socketObj.id 등 계속하다가

도저히 알수가 없어서

튜터님을 찾아가서 해결했다.

 

@Schema(options)
export class Chatting extends Document {


  // @Prop({
  //   type: {
  //     _id: { type: Types.ObjectId, required: false, ref: 'sockets' },
  //     id: { type: String },
  //     username: { type: String, required: false },
  //   },
  // })
  @Prop({ required: true })
  @IsString()
  @IsNotEmpty()
  nickname: string;
  // nickname: SocketModel;

  @Prop({
    required: false,
  })
  @IsNotEmpty()
  @IsString()
  message: string;
}

export const ChattingSchema = SchemaFactory.createForClass(Chatting);

 

주석으로 처리한 prop(속성)값을 강의에서 본대로 작성했는데

type쪽이 유형을 정해버려서 에러가 발생했다.

그전에도 required: true; 에서 문제가 발생했다.

테스트하는 과정이라 닉네임도 없고 id도 없다보니

없는 변수를 필수로 처리해서 에러가 발생한것이었다.

 

 

4. 알게 된 점

 

몽고디비, 몽구스 연결시도 10회를 채우기로 했다.

도대체 뭐가 문제인지 궁금했다. 상세메시지를 봐야 해결할 수 있지 않을까?

상세 에러문구

강의보고 따라 작성한 옵션이고, 나는 최신몽구스를 설치한 것 같은데

해당 옵션은 지원하지 않는다고 한다. 주석처리하니 문제가 해결되었다.

[validation failed] 이것은 몽구스 model관련 에러니까 prop(속성)을 자세히 살펴보자!

 

728x90
반응형
728x90
반응형

이번 주 알게 된 점

최종프로젝트 1주차를 시작했다.

나는 소켓I.O 부분을 맡아 인스타그램에 있는 DM과 상태알림창을 만들기로 했다.

 

이번주 목표 달성 여부

이번주 목표인 DM기능을 구현했다.

하지만 데이터베이스와 연동된 DM이 아니라

로컬환경에서 데이터없이 휘발성으로 채팅하는 기능이다.

 

다음주 목표 세우기

DM기능 데이터베이스 연결

실제 서비스 가능할 정도로 구현

728x90
반응형
728x90
반응형

나에게 닥친 가장 큰 문제는

소켓관련 채팅 및 알람 ERD작성이 문제였다.

 

그리고 해당 문제에 대해 공부하던 도중

채팅관련 DB는 SQL보다 mongoose가 좋다는 사실을 알았고

강의와 블로그를 보며 데이터 연결을 시도했지만 에러가 계속 발생했다.

 

여러차례 시도하던중 데이터연결실패 10회이후,

상세한 에러문구를 발생한다는 것을 알았고 해당 문구를 보고 해결완료.

 

https://pyoja.tistory.com/208

 

[에러일기] 9회차 - 몽구스 데이터베이스 연결실패

1. 문제 [mongoosemodule] unable to connect to the database 강의와 문서들을 보며 몽구스를 연결시도했다. 그런데 서버실행만 하면 계속 위와 같은 문구가 발생하여 나를 괴롭혔다......ㅠㅠ 수차례 여러가지

pyoja.tistory.com

 

DB연결이 안될때가 정말 화가 나고 짜증난다.... 10번 기다려서 상세에러문구 받는걸 잊지 말아야지.

728x90
반응형
728x90
반응형

1. 문제

[mongoosemodule] unable to connect to the database

강의와 문서들을 보며 몽구스를 연결시도했다.

그런데 서버실행만 하면 계속 위와 같은 문구가 발생하여 나를 괴롭혔다......ㅠㅠ

수차례 여러가지를 시도 했는데 안되니까 멘붕

 

2. 시도해본 것들

import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ChatBackEndModule } from './chatBackEnd/chatBackEnd.module';
import { ChatFrontEndModule } from './chatFrontEnd/chatFrontEnd.module';
import { TypeOrmConfigService } from './common/config/typeorm.config.service';
import * as mongoose from 'mongoose'; //몽구스
import { LoggerMiddleware } from './logger/logger.middleware'; //미완성 로그 => 강의를 중구난방으로 들어서 찾기 어려움

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    //몽구스 연결 process.env.MONGO_URL
    MongooseModule.forRoot(process.env.MONGO_URL, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
      // useCreateIndex: true,
      // useFindAndModify: false,
    }),

    TypeOrmModule.forRootAsync({
      useClass: TypeOrmConfigService,
    }),
    ChatBackEndModule,
    ChatFrontEndModule,
  ],
})
//몽구스 추가설정
export class AppModule implements NestModule {
  private readonly isDev: boolean = process.env.MODE === 'dev' ? true : false;
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes('*');
    mongoose.set('debug', this.isDev);
  }
}

app.module.ts의 구성이었다.

시도해본 것은 환경설정값 대신 직접 입력하거나,

ConfigModule의 순서를 바꾸거나

useNewParser을 주석처리하거나 온갖 해결방법을 찾아서 다 시도해봤지만 실패했다.

 

3. 해결과정

 

방법을 찾던 도중 스택오버플로우에서 다음과 같은 글귀를 봤다

https://stackoverflow.com/questions/70730514/unable-to-connect-to-the-database-retrying

데이터 연결하면 Retrying(3)... (4)...

이렇게 뜨는데 상세한 에러 문구가 없어서 뭐 어쩌라고! 라는 심정이었다

그런데 10번만 기다리면 상세문구를 준다고?

 

4. 알게 된 점

 

몽고디비, 몽구스 연결시도 10회를 채우기로 했다.

도대체 뭐가 문제인지 궁금했다. 상세메시지를 봐야 해결할 수 있지 않을까?

상세 에러문구

강의보고 따라 작성한 옵션이고, 나는 최신몽구스를 설치한 것 같은데

해당 옵션은 지원하지 않는다고 한다. 주석처리하니 문제가 해결되었다.

 

역시 에러코드가 자세히 나와야 문제를 해결할 수 있다.

몽구스가 10회 시도후 에러문구를 발생시킨다는것을 잊지말자.

728x90
반응형
728x90
반응형

<1> 몽고DB 관련 내용

데이터베이스란? 데이터의 집합, 저장소

RDBMS (관계형 데이터 베이스)

NOSQL (비관계형 데이터 베이스)

 

https://www.mongodb.com/ko-kr

위에 사이트에서 가입후 프로젝트 생성 -> Clusters 생성

(개발환경은 ALLOW ACCES가 맞는데, 배포시엔 바꿔야하는지 모름)

순서대로 모두 진행하고 파일을 다운받는다. 아래는 설치한 프로그램 실행화면

해당 URL은 비밀번호와 맨뒤에 데이터베이스 이름이 들어있다.

연결후에 데이터베이스를 만들때 오류가 발생했다.

 

오류발생

user is not allowed to do action [createCollection] on [nest.chatMessage]

 

해당 문제에 대해 검색해보니 atals에서 사용자 권한설정을 안해줘서 나타나는 오류라는 것

atals 웹사이트에 들어가서 로그인 후 클러스터의 Database Access 를 클릭해 사용자 Edit를 누르면

권한설정

출처 : https://yamea-guide.tistory.com/entry/atlas-MongoError-user-is-not-allowed-to-do-action-find-on

위와 같이 설정후 만들면 에러해결 완료

 

<몽구스 연결하기>

https://bit.ly/3moGwZG  강의자료 깃허브

더보기

Mongodb는 데이터베이스 자체 이고 Mongoose는 Mongodb 의 객체 모델링 도구 입니다.
Node.js의 관점에서 mongodb 는 mongodb 인스턴스와 상호 작용하기위한 기본 드라이버 이며

mongoose 는 MongoDB 의 객체 모델링 도구 입니다.
-> 접근 방식의 차이

npm i @nestjs/mongoose mongoose

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ChatBackEndModule } from './chatBackEnd/chatBackEnd.module';
import { ChatFrontEndModule } from './chatFrontEnd/chatFrontEnd.module';
import { TypeOrmConfigService } from './common/config/typeorm.config.service';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    TypeOrmModule.forRootAsync({
      useClass: TypeOrmConfigService,
    }),
    //몽구스 연결
    MongooseModule.forRoot(process.env.MONGO_URL, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
      //useCreateIndex: true,		에러발생 코드 주석처리
      //useFindAndModify: false,
    }),
    ChatBackEndModule,
    ChatFrontEndModule,
  ],
})
export class AppModule {}

위와 같이 설정후 서버를 켰는데 에러가 발생한다.

서버를 키면 데이터베이스와 연결하지 못하고 10번까지 연결을 시도한다.

모두 시도한후 상세 에러 메시지를 알려주니 연결실패시 꼭 기다리자

https://pyoja.tistory.com/208

 

[에러일기] 9회차 - 몽구스 데이터베이스 연결실패

1. 문제 [mongoosemodule] unable to connect to the database 강의와 문서들을 보며 몽구스를 연결시도했다. 그런데 서버실행만 하면 계속 위와 같은 문구가 발생하여 나를 괴롭혔다......ㅠㅠ 수차례 여러가지

pyoja.tistory.com

 

<몽구스 명령어 정리>

몽구스 공식홈페이지 (https://mongoosejs.com/docs/api/mongoose.html)

인파 명령어 정리 (https://bit.ly/3Ymz12X)

 

자주 사용되는 명령어 정리

// 1. 새문서 만들기
const newDoc = new MyModel({ field1: 'value1', field2: 'value2' });
await newDoc.save();

// 2. 문서찾기
const docs = await MyModel.find({ field1: 'value1' }).exec();

// 3. 문서 업데이트
await MyModel.updateOne({ field1: 'value1' }, { field2: 'newvalue2' }).exec();

// 4. 문서 삭제
await MyModel.deleteOne({ field1: 'value1' }).exec();

사용예시)

// Create a new document
const newDoc = new MyModel({ field1: 'value1', field2: 'value2' });
await newDoc.save();

// Find the document
const doc = await MyModel.findOne({ field1: 'value1' }).exec();

// Update the document
doc.field2 = 'newvalue2';
await doc.save();

// Delete the document
await MyModel.deleteOne({ field1: 'value1' }).exec();

<2> Nest.js

비주얼스튜디오 단축키

왼쪽창 숨기기/보이기 = 컨트롤 + b

터미널 닫기/열기 = 컨트롤 + j

 

 

<3> 랜덤 채팅 웹앱(소켓 프로그래밍)

서버사이드 렌더링 : 서버에서 html 렌더링해서 브라우저로 보여준다 (nestjs)

클라이언트 사이드 렌더링 : 클라이언트 사이드에서 html 렌더링한다. (클라이언트 사이드 =  브라우저)

 

소켓 : 입구, 콘센트

소켓 연결 방식 : 양방향

(*중요*) emit과 on 으로 서버와 클라이언트가 소통합니다. 

 

예를들어

서버 = emit('sendMessage') 로 메시지를 전송하면,  [이벤트네임 : sendMessage]

클라이언트 = on('sendMessage')으로 메시지를 받을 수 있습니다.

이안에 또 emit을 넣고 서버에서 on으로 받는 로직을 만들어 on 과 emit의 관계를 만들어야 합니다.

 

const socket = io('/user');  //클라이언트

@WebSocketGateway({ namespace: 'user'}); //서버

// 위와 같이 url을 연결할 수 있다.

쓸모있는지 모르지만 몰랐던 사실이라 적음

// chats.gateway.ts
socket.broadcast.emit('user_connected', username);
return username;

// index.js
sokect.on('user_connected', (username) => {
   console.log(`${username} connected`);
 });
 
 // broadcast로 자신을 제외한 모든 소켓에 데이터를 전달할 수 있다.

emit과 on에 있는 'user_connected'는 이벤트 네임이라 부르며 서로 연결된 관계이다.

 

채팅 기본 설정으로 입력하는 값을 담아서 html에 보여주는 기본 구조

 

2개이상의 DB를 사용한다면 위와 같이 레포지토리에 2개 이상 주입시키면 됩니다.

 

models 폴더 생성

//* chattings.model.ts

import { IsNotEmpty, IsString } from 'class-validator';
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document, SchemaOptions, Types } from 'mongoose';
import { Socket as SocketModel } from './sockets.model';

const options: SchemaOptions = {
  collection: 'chattings', //db이름을 설정
  timestamps: true,
};

@Schema(options)
export class Chatting extends Document {
  @Prop({
    type: {
      _id: { type: Types.ObjectId, required: true, ref: 'sockets' },
      id: { type: String },
      username: { type: String, required: true },
    },
  })
  @IsNotEmpty()
  user: SocketModel;

  @Prop({
    required: true,
  })
  @IsNotEmpty()
  @IsString()
  chat: string;
}

export const ChattingSchema = SchemaFactory.createForClass(Chatting);

@Schema(options)

@nestjs/mongoose는 새로운 몽구스 스키마를 선언하는 라이브러리의 데코레이터입니다. 
options스키마에 대한 추가 구성 옵션을 지정하는 데 사용할 수 있는 선택적 매개변수입니다.


@Prop

@Prop는 스키마에서 속성을 선언하는 라이브러리의 데코레이터입니다 

//* sockets.model.ts

import { IsNotEmpty, IsString } from 'class-validator';
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document, SchemaOptions } from 'mongoose';

const options: SchemaOptions = {
  id: false,
  collection: 'sockets',
  timestamps: true,
};

@Schema(options)
export class Socket extends Document {
  @Prop({
    unique: true,
    required: true,
  })
  @IsNotEmpty()
  @IsString()
  id: string;

  @Prop({
    required: true,
  })
  @IsNotEmpty()
  @IsString()
  username: string;
}

export const SocketSchema = SchemaFactory.createForClass(Socket);
//* chatBackEnd.module.ts

import { SocketSchema, Socket as SocketModel } from './models/sockets.model';
import { Chatting, ChattingSchema } from './models/chattings.model';
import { MongooseModule } from '@nestjs/mongoose';
import { Module } from '@nestjs/common';
import { ChatBackEndGateway } from './chatBackEnd.gateway';
import { ChatRoomService } from './chatRoom.service';

@Module({
  imports: [
    MongooseModule.forFeature([
      { name: Chatting.name, schema: ChattingSchema },
      { name: SocketModel.name, schema: SocketSchema },
    ]),
  ],
  providers: [ChatBackEndGateway, ChatRoomService],
})
export class ChatBackEndModule {}

소켓모델과 채팅모델을 chatBackEnd.module.ts에 등록합니다.

name과 schema에 대해 설명하겠습니다.

 

name : 몽구스 모델의 이름을 지정합니다.

            채팅 메시지에 대한 Mongoose 모델의 이름인 "Chatting" 문자열을 반환하는 클래스 의 정적 속성입니다.

schema : 몽구스 모델의 스키마를 지정합니다. 메시지 텍스트, 보낸 사람, 받는 사람 및 타임스탬프를 포함하여

               모델 의 속성과 필드를 정의하는 Mongoose 스키마입니다 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90
반응형

'코딩공부 > Nest.js' 카테고리의 다른 글

Next.js의 서버 렌더링  (0) 2024.11.01
[🔥기록용🔥] Nest.js 기능구현때 배운 점  (0) 2023.03.11
🔥TypeORM 간단정리🔥  (0) 2023.03.09

+ Recent posts