728x90

nestjs에서 jest를 이용한 End2End 테스트 케이스를 작성하였습니다.

src/user/user.controller.spec.ts 파일에 사용자 추가/수정/삭제/조회에 대한 테스트 케이스를 작성하였습니다.

  1. End2End 데이터 기준의 validate 테스트
  2. 로그인 Mock 객체 주입 테스트
  3. repository Mock 객체 테스트

전체 테스트 케이스 실행은 다음의 명령어로 할 수 있습니다.

node run test

특정 테스트 케이스 실행은 다음 명령어로 할 수 있습니다.

node node_modules/jest/bin/jest.js src/user/user.controller.spec.ts 

테스트 케이스를 이용하면 코드의 오류를 빠르게 찾아낼 수 있습니다.
그 외에도 플로우차트 기반으로 테스트 케이스를 작성하여 명세에 알맞은 프로그램을 작성할 수도 있고요!

전체 코드 바로 가기 : https://github.com/lahuman/nestjs_101

Posted by lahuman

댓글을 달아 주세요

728x90

오늘 설명은 Controller 기반의 테스트에서 다음 내용입니다.

  1. Repository 객체를 Mock으로 주입
  2. Connection 객체를 Mock으로 주입
  3. mockAuthGuard 객체를 Mock으로 주입하여 로그인 처리
  4. 첨부파일 업로드

Mock 객체 생성

자동으로 만들어진 테스트 케이스는 아래와 같습니다

import { Test, TestingModule } from '@nestjs/testing';
import { Controller } from './my.controller';

describe('Controller', () => {
  let controller: Controller;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [Controller],
    }).compile();

    controller = module.get<Controller>(Controller);
  });

  it('should be defined', () => {
    expect(controller).toBeDefined();
  });
});

Controller의 소스는 기본적으로 service를 호출하고, service에서는 Entity를 이용하여 Repository를 Inject 합니다.

Inject에 필요한 Mock객체들을 생성을 합니다.
내부 구현이 필요 없을 경우 jest.fn()를 활용하면 쉽게 처리 할 수 있습니다.

class MockRepository {

  async save(any) {
    return new OssAtachFileDEntity({
      "refSeq": 1,
      "refCd": "RE",
      "regrId": "12345",
      "modrId": "12345",
      "fileName": "첨부파일 테스트.pdf",
      "filePath": "202106/e55daf47-af60-4e8d-9e54-67cbfc680556",
      "size": 73666,
      "fileExtension": "pdf",
      "seq": 2
    });
  }
  async find() {
    return [new OssAtachFileDEntity({
      "refSeq": 1,
      "refCd": "RE",
      "regrId": "12345",
      "modrId": "12345",
      "fileName": "첨부파일 테스트.pdf",
      "filePath": "202106/e55daf47-af60-4e8d-9e54-67cbfc680556",
      "size": 73666,
      "fileExtension": "pdf",
      "seq": 2
    })];
  }
  async findOne(any) {
    return new OssAtachFileDEntity({
      "refSeq": 1,
      "refCd": "RE",
      "regrId": "12345",
      "modrId": "12345",
      "fileName": "첨부파일 테스트.pdf",
      "filePath": "202106/e55daf47-af60-4e8d-9e54-67cbfc680556",
      "size": 73666,
      "fileExtension": "pdf",
      "seq": 2
    });
  }

  async remove() {

  }
}

const mockConnection = () => ({
  transaction: jest.fn(),
  createQueryRunner: () => ({
    connect: jest.fn(),
    startTransaction: jest.fn(),
    commitTransaction: jest.fn(),
    rollbackTransaction: jest.fn(),
    release: jest.fn(),
    manager: {
      save: (r => r)
    }
  })
});

const mockAuthGuard: CanActivate = {
  canActivate: (context: ExecutionContext) => {
    const request = context.switchToHttp().getRequest();
    request.user = {
      id: '12345',
      name: "임광규",
      email: 'lahuman@daum.net'
    };
    return request.user;
  }
};

Mock 객체 주입

구현한 Mock 객체들을 module에 Inject 처리를 합니다.

 let app: INestApplication;
  let httpService: HttpService;
  let controller: Controller;

  beforeEach(async () => {

    const module: TestingModule = await Test.createTestingModule({
      imports: [HttpModule, ConfigModule.forRoot({ isGlobal: true })],
      controllers: [Controller],
      providers: [Service,
        {
          provide: getRepositoryToken(OssReqMEntity),
          useClass: MockRepository,
        },
        {
          provide: Connection,
          useFactory: mockConnection
        }
      ],
    })
      .overrideGuard(AuthenticatedGuard).useValue(mockAuthGuard)
      .compile();
    app = module.createNestApplication();
    httpService = module.get<HttpService>(HttpService);
    await app.init();

    controller = module.get<Controller>(Controller);
  });

첨부파일 테스트

 it('첨부파일 추가', async () => {
    const response = await request(app.getHttpServer())
      .post("/attach-file/upload")
      .attach('file', '/path/file-name')
      .expect(201);
    expect(JSON.parse(response.text).status).toEqual(true);
  });

로그인 처리 테스트

로그인의 경우 PASSPORT-SAML 방식을 이용하였으며 Request에 user라는 객체를 이용합니다.

등록된 결과에 userId가 12345인지 확인하는 테스트를 진행합니다.

 it('조회', async () => {
    const response = await request(app.getHttpServer())
      .get('/1')
      .expect(200);
    expect(JSON.parse(response.text).regrId).toEqual("12345");
  });

이상으로 기본적인 Nestjs 테스트 케이스를 사용해보았습니다.

은근 어려웠네요.

Posted by lahuman

댓글을 달아 주세요

728x90

기존 function에서 오류가 날 경우 봇으로 메시지 발송 기능을 구현 하려고 합니다.

express에서는 middleware를 활용했었는데, 순수한 javascript에서는 어떻게 해야할지 검색을 해보니 Is there a way to add try-catch to every function in Javascript? 를 확인 할 수 있었습니다.

var tcWrapper = function(f) {
    return function() {
        try {
            f.apply(this, arguments);
        } catch(e) {
            customErrorHandler(e)
        }
    }
}

위 예제의 문제는

  1. 결과 값 return 처리가 안되었다.
  2. async (비동기) 처리에서 오류 발생시 catch가 안됩니다.

이를 해결하기 위해서 다음과 같이 해결하였습니다.

// 예제 function
const example = function ({ data }) {
  return new Promise((res, rej) => setTimeout(() => { rej({ status: 100, id: data.id, name: "임광규" }) }, 1000));
}

// middleware 구현
const wrapper = function (f) {
  return async function () {
    try {
      return await f.apply(this, arguments);
    } catch (err) {
      try {
        const { statusCode: status } = JSON.parse(err);
        if (status > 400) {
          console.log("status is over the 400")
        }
      } catch (e) { console.log(e) };

      throw err;
    }
  }
};

// 사용 예제 
(async () => {
  const fnc = wrapper(example);
  const result = await fnc({ data: { id: "23201" } });
  console.log(result)
})();
  1. return 구문 추가로 최종 결과값 전달
  2. async, await 키워드 추가로 비동기에 오류 누락 문제 해결
  3. throw 구문으로 오류 전파

사용은 module.exportfunction을 감싸서 처리 합니다.

module.exports = {
  getUsers: wrapper(getUsers),
}

참고자료

Posted by lahuman

댓글을 달아 주세요

728x90

Workplace Export

워크플레이스의 관리자 패널에서는 특정 Group의 게시글을 export를 제공하지 않습니다.

이 프로젝트는 Workplace의 특정 Group의 게시글을 다운 받는 기능을 제공합니다.
한번에 다운받을 게시글의 수는 .env에서 변경이 가능합니다. 너무 큰 숫자의 경우 Workplace 서버에서 오류가 발생할 수 있습니다.
(권장: 100, 최대 : 500, 테스트에서는 1000도 가능하였으나, 오류가 간간히 발생했습니다.)
workplace 게시글 + 댓글을 xlsx 형식으로 다운로드 합니다.

Screen

그룹 정보 조회

  • 그룹 ID를 기준으로 그룹 정보가 표기

1번째 이후 게시글 다운로드 시

  • 게시글 다운로드 다음 으로 UI 변경

모든 게시글 다운로드 시

  • 알림 표기

잘못된 그룹 ID 입력시

결과 예제

Export Example

Table of Contents

설치 & 설정 & 정보


Installation

  • 설치를 위해서는 기본적으로 NODEJS 14.x 이상의 버젼이 필요합니다.

Backend

  • nestjs 기반으로 작성되었습니다.
  • PATH : backend

.env 설정은 _env 파일을 .env로 변경하여서 Key에 알맞은 값을 설정 하면 됩니다.
또는 아래 샘플을 이용하셔요.
WP_TOKEN는 workplace 관리자 화면에서 생성한 맞춤 통합의 토큰 값입니다
해당 통합은 게시물, 댓글 사용자의 정보를 조회하는 권한을 주어야 합니다.

NODE_ENV=deployment
PORT=3000
WP_GRAPH_URL=https://graph.facebook.com
WP_TOKEN= # workplace Token 발급 필요
DEFAULT_LIMIT=100

실행

$ npm install
$ npm run start

서버가 문제 없이 기동이 되면 Swagger UI을 확인하세요.

Frontend

  • ReactJS로 작성되어 있습니다.
  • PATH : frontend

.env 설정은 _env 파일을 .env로 변경하여서 Key에 알맞은 값을 설정 하면 됩니다.
또는 아래 샘플을 이용하셔요.

REACT_APP_API=http://localhost:8080 # API SERVER 주소 
REACT_APP_WORKPLACE=https://{domain}.workplace.com # workplace 주소
REACT_APP_LIMIT=100 # 게시글 다운수 (backend와 같은 수 화면 표기용)

실행

$ npm install
# npm run start

Workplace

Workplace은 페이스북에서 개발한 엔터프라이즈 연결 플랫폼입니다.
그룹 사용, 인스턴스 메시징 및 뉴스 피드를 포함합니다.

게시물의 반응을 확인하기 위해서 관리자 페이지에서 맞춤 통합을 생성해야 합니다.

통합 생성후 다음 3개의 통합 권한(그룹 콘텐츠 읽기(필수), 사용자 이메일 읽기(옵션), 그룹 멤버 읽기(옵션))을 할당해야 합니다.


History

  • v1.0 : workplace Export

License

License

Posted by lahuman

댓글을 달아 주세요

728x90

md5-lite

프로젝트 바로가기

파일을 청크(Chunk) 사이즈 처리를 해서 성능 향상을 목적으로 만들어진 모듈입니다.
파일 크기가 200000byte(0.2MB) 이상일 경우 초기 100000byte (0.1MB)와 마지막 100000byte을 이용하여 md5 hash 처리 합니다.
그보다 크기가 작을 경우 전체 데이터의 전체를 md5 hash 처리 합니다.

사용법은 다음과 같습니다.

Installation

npm install md5-lite --save
yarn add md5-lite
bower install md5-lite --save

Usage

Javascript

const {md5Lite} = require('md5-lite');
console.log(md5Lite('./filepath'));
0486c21a4d40d0f3b0bdad3925db439e

TypeScript

import {md5Lite} from 'md5-lite';
console.log(md5Lite('./filepath'))
0486c21a4d40d0f3b0bdad3925db439e

License

License

Posted by lahuman

댓글을 달아 주세요

728x90

MSSQL POOL을 Express 환경에서 사용하기

node-mssql의 예제를 참고로 다음과 같이 사용하고 있었습니다.

const sql = require('mssql')

// async/await style:
const pool1 = new sql.ConnectionPool(config);
const pool1Connect = pool1.connect();

pool1.on('error', err => {
    // ... error handler
})

async function messageHandler() {
    await pool1Connect; // ensures that the pool has been created
    try {
        const request = pool1.request(); // or: new sql.Request(pool1)
        const result = await request.query('select 1 as number')
        console.dir(result)
        return result;
    } catch (err) {
        console.error('SQL error', err);
    }
}

문제는 간간히 - Error: Already connecting to database 와 같은 오류가 발생했습니다.

이유로 매번 요청시마다, connect를 연결하려고 하였기 때문이었습니다.

해결 방법으로는 How can I use a single mssql connection pool across several routes in an Express 4 web application?에서 제공하는 db.js를 만들어서 사용하면 됩니다.

const sql = require("mssql");
const config = {
  user: process.env.DB_MSSQL_USER,
  password: process.env.DB_MSSQL_PASSWORD,
  server: process.env.DB_MSSQL_IP, // You can use 'localhost\\instance' to connect to named instance
  database: process.env.DB_MSSQL_DB,
  options: {
    encrypt: true, // Use this if you're on Windows Azure
  },
  pool: {
    max: 5,
    min: 1,
    idleTimeoutMillis: 30000,
  },
};

const poolPromise = new sql.ConnectionPool(config)
  .connect()
  .then((pool) => {
    console.log("Connected to MSSQL");
    return pool;
  })
  .catch((err) => console.log("Database Connection Failed! Bad Config: ", err));

module.exports = {
  sql,
  poolPromise,
};

오늘의 삽질도 끝~

참고자료

Posted by lahuman

댓글을 달아 주세요

728x90

NAVER CLOUD PLATFORM API를 Typescript 기반에서 사용하기

회사의 메일 발송은 NAVER CLOUD PLATFORM API를 이용하고 있습니다.

NAVER CLOUD PLATFORM API를 참조하면 인증키를 생성해서 API를 호출 해야 합니다.

자바를 사용할 경우 쉽게 만들수 있는데, javascript 버젼의 경우 CryptoJS v3.1.2를 사용하는 가이드를 주고 있습니다.

문제는 nodejs기반에선는 CryptoJS v3.1.2보다는 crypto-js를 많이 사용합니다.

다음 코드는 crypto-js를 사용해서 NAVER CLOUD PLATFORM API를 연동한 예제 입니다.

메일 발송 예제

import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import { SendMailDto } from './dto/sendmail.dto';
import { MailResultDto } from './dto/mailresult.dto';
import CryptoJS = require("crypto-js");
import Base64 = require('crypto-js/enc-base64');
import { HttpService } from "@nestjs/common";

@Injectable()
export class MailService {
  constructor(private httpService: HttpService) { }

  private makeSignature(timestamp: string): string {
    const space = " ";                // one space
    const newLine = "\n";                // new line
    const method = "POST";                // method
    const url = "/api/v1/mails";    // url (include query string)
    // const timestamp = new Date().getTime();            // current timestamp (epoch)
    const accessKey = process.env.MAIL_ACCESS_KEY;            // access key id (from portal or Sub Account)
    const secretKey = process.env.MAIL_SECRET_KEY;            // secret key (from portal or Sub Account)
    let baseSignature = (method);
    baseSignature += (space);
    baseSignature += (url);
    baseSignature += (newLine);
    baseSignature += (timestamp);
    baseSignature += (newLine);
    baseSignature += (accessKey);

    const hmac = CryptoJS.HmacSHA256(baseSignature, secretKey);
    return Base64.stringify(hmac);
  }

  public async sendMail(sendMailDto: SendMailDto): Promise<MailResultDto> {
    const timestamp: string = new Date().getTime().toString();
    return this.httpService.post('https://mail.apigw.ntruss.com/api/v1/mails', sendMailDto, {
      headers: {
        "x-ncp-apigw-timestamp": timestamp,
        "x-ncp-iam-access-key": process.env.MAIL_ACCESS_KEY,
        "x-ncp-apigw-signature-v2": this.makeSignature(timestamp),
        "Content-Type": "application/json"
      }
    }).toPromise().then(({ data }) => data)
      .catch(e => {
        this.logger.error(e);
        throw new HttpException("Bad Request.", HttpStatus.BAD_REQUEST);
      });
  }
}

crypto-js를 Typescript 기반에서 사용할때 주의할 것은, import 방식을 다음과 같이 사용하여야 합니다.

import CryptoJS = require("crypto-js");
import Base64 = require('crypto-js/enc-base64');

어렵고도쉬운문제

참고자료

Posted by lahuman

댓글을 달아 주세요

Nestjs tutorial

NodeJS 2021. 1. 11. 04:26
728x90

Nestjs tutorial

1. 프로젝트 생성하기

nestjs cli 를 이용하면 쉽게 프로젝트를 생성 할수 있습니다.

# nestjs cli 설치
$ npm i -g @nestjs/cli
# 프로젝트 생성
$ nest new project-name

2. OpenAPI 설정

다음 라이브러리를 설치합니다.

$ npm install --save @nestjs/swagger swagger-ui-express

이후 main.ts에 SwaggerModule 설정을 합니다

# main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from "@nestjs/platform-express";
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';

async function bootstrap() {

  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  const options = new DocumentBuilder()
    .setTitle('프로젝트 명')
    .setDescription('프로젝트 설명')
    .setVersion('1.0')
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('docs', app, document);

  await app.listen(process.env.PORT);
}
bootstrap();

3. Validation

request 요청에 대한 Validation(검증) 처리를 위해
다음 라이브러리의 설치가 필요 합니다.

$ npm install class-validator

Global 설정을 main.ts에 추가 합니다.
Transform payload objects 설정을 하여 자동 변환 처리를 합니다.

# main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from "@nestjs/platform-express";
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {

  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  app.useGlobalPipes(new ValidationPipe({transform: true})); // Validate with 자동 변환 처리
  const options = new DocumentBuilder()
    .setTitle('프로젝트 명')
    .setDescription('프로젝트 설명')
    .setVersion('1.0')
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('docs', app, document);

  await app.listen(process.env.PORT);
}
bootstrap();

이후 예제는 auto-validation에서 확인하세요.

4. Configuration

express에서는 dotenv를 사용하였는데, nestjs에서는 Configuration이 제공 됩니다.
설치는 아래와 같습니다.

$ npm i --save @nestjs/config

사용법은 app.module.ts에 선언을 하여서 사용합니다. isGlobal 설정을 해두면 다른 모듈에서 imports 하지 않고 사용이 가능합니다.
기본적으로 .env 파일을 읽어서 변수화 하여 사용합니다.

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [ConfigModule.forRoot({  isGlobal: true })],
})
export class AppModule {}

더 자세한 예제는 Using the ConfigService를 참조하세요.

4. Logger

nestjs에서는 기본적으로 Logger class를 제공합니다.
main.js에서 ApplicationModule에서 logger 옵션을 이용해서 레벨을 설정할 수 있습니다.
레벨은 'log', 'error', 'warn', 'debug', 'verbose' 이 있습니다.

const app = await NestFactory.create(ApplicationModule, {
  logger: ['error', 'warn'],
});
await app.listen(3000);

사용법은 Using the logger for application logging 같이 주입하여 사용이 가능합니다.

import { Logger, Injectable } from '@nestjs/common';

@Injectable()
class MyService {
  private readonly logger = new Logger(MyService.name);

  doSomething() {
    this.logger.log('Doing something...');
  }
}

5. session

세션은 express를 사용할 경우 express-session 모듈을 설치해서 사용합니다.

$ npm i express-session

사용법은 main.ts에 아래 코드를 추가합니다.(이는 express-session 사용법을 자세히 보세요.)

import * as session from 'express-session';
// somewhere in your initialization file
app.use(
  session({
    secret: 'my-secret',
    resave: false,
    saveUninitialized: false,
  }),
);

6. helmet & cors 설정

helmet 과 cors 설정은 다른 설정 함수 보다 먼저 설정되어야 합니다.
만약 경로를 정의한 후 helmet과 cors를 설정할 경우 이미 설정된 경로의 미들웨어는 적용되지 않을 수 있습니다.

helmet은 http 해더를 적정하게 설정하여 웹 취약점으로 부터 앱을 보호 합니다.
설치

$ npm i --save helmet

사용법

import * as helmet from 'helmet';
// somewhere in your initialization file
app.use(helmet());

cors는 다른 도메인에서 리소스를 요청 할 수 있도록하는 설정입니다.
설치는 따로 필요 없습니다. 사용법은 아래와 같습니다.

const app = await NestFactory.create(AppModule);
app.enableCors();
await app.listen(3000);

main.ts 예제

다음은 제가 사용한 예제 입니다.

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from "@nestjs/platform-express";
import * as helmet from 'helmet';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ValidationPipe } from '@nestjs/common';
import * as session from 'express-session';
import * as passport from 'passport';
import flash = require('connect-flash');

async function bootstrap() {

  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  app.setGlobalPrefix('api'); // prefix 설정
  app.useGlobalPipes(new ValidationPipe({ transform: true })); // validate 사용 설정
  app.use(helmet({
    contentSecurityPolicy: false,
  })); // helmet 설정과 CSP 제외 (google analytics 사용시 제외 해야함)
  app.enableCors({
    origin: [
      /^(.*)/,
    ],
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
    preflightContinue: false,
    credentials: true,
    optionsSuccessStatus: 204,
    allowedHeaders:
      'Origin,X-Requested-With,Content-Type,Accept,Authorization,authorization,X-Forwarded-for',
  }); // cors 설정 credentials 설정을 해야 credentials 정보도 함께 전달함

  const options = new DocumentBuilder()
    .setTitle('프로젝트 명')
    .setDescription('프로젝트 설명')
    .setVersion('1.0')
    .addBearerAuth() // openapi 문서에서 권한 처리 추가
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('docs', app, document); // openapi 사용

  app.use(session({
    secret: process.env.SECCRET || 'keyboard cat',
    resave: false,
    saveUninitialized: false,
  })); // session 사용
  // passport 설정
  app.use(passport.initialize()); 
  app.use(passport.session());
  // request에 값을 추가 하는 flash 추가 
  app.use(flash());

  await app.listen(process.env.PORT);
}
bootstrap();

상세한 예제는 다음 2개의 프로젝트를 참고 하세요.

  1. nestjs-realworld-example-app
  2. test-auth-chapter-sample

참고자료

Posted by lahuman

댓글을 달아 주세요

typeorm에서 merge 예제

NodeJS 2021. 1. 11. 04:26
728x90

typeorm에서 merge 예제

데이터가 있을 경우 update, 없을 경우 insert를 처리 하는 코드 예제 입니다.

await this.eventsRepository
      .createQueryBuilder()
      .insert()
      .into(Event)
      .values(event)
      .orUpdate({ conflict_target: ['wp_id'], overwrite: ['cntnt', 'srch_wrd_seq', 'writr_nm', 'writr_id', 'tgtr_nm', 'tgtr_id', 'mod_dtm'] })
      .execute();

orUpdate의 conflict_target에 중복 키 값을 넣고 update할 목록을 overwrite에 넣으면 됩니다.

여기서 주요한건, 모두 DB필드 기준으로 입력하여야 합니다.

참고자료

Posted by lahuman

댓글을 달아 주세요

728x90

Mongoose에서 Array 내용 수정 후 .save()를 호출해도 동작하지 않는 현상

다음과 같은 mongo Model이 존재 할때,

const mongoose = require('mongoose');

const { Schema } = mongoose;

const Confirm = new Schema({
  type: { type: String, require: true, index: true },
  pgm_id: { type: Number, require: true, index: true },
  confirm: { type: Array, index: true },
  brd_dtm: { type: Date, require: true, index: true },
}, { timestamps: true });

module.exports = mongoose.model('Confirm', Confirm);

다음과 같은 데이터가 있다고 가정했을때,

{
    type: 'A',
    pgm_id: 1234,
    confirm:[0,0,0],
    brd_dtm:  ISODate("2020-11-26T05:51:37.970Z")

}

모델을 조회 후 수정하였고, 저장했다.

const result = await Confirm.findOne({pgm_id: '1234'});

result.confirm[3] = 10;

await result.save();

console.log(await Confirm.findOne({pgm_id: '1234'}));

결과는 데이터가 변경되지 않습니다.

Array의 경우 수정을 하고 저장을 해도 처리가 되지 않습니다.
단 Array를 새로 만들어서 넣을 경우는 반영됩니다.

하지만 매번 Array를 새로 만들기 보다 쉽게 하는 방법은 다음과 같습니다.

const result = await Confirm.findOne({pgm_id: '1234'});

result.confirm[3] = 10;

//변경된 사항을 강제 처리
result.markModified('confirm');

await result.save();

이렇게 하는 방식도 있다!

참고자료

Posted by lahuman

댓글을 달아 주세요