sequelize에서 alias 사용하여 검색하는 방법

web/node.js|2018. 12. 19. 21:41

sequelize에서 검색을 할 때 alias를 줘서 검색하는 방법은 다음과 같다. 

생각보다 간단하다.


1
2
3
await This.User.findOne({
  attributes: ['id', ['name''userName']] //id, first AS firstName
});
cs


댓글()

sequelize에서 timezone 설정 추가

web/node.js|2018. 11. 26. 22:56

sequelize를 통해 datetime 필드에 값을 삽입해봤을 때 계속해서 값이 UTC 시간대로 들어가게 되었다.


그래서 해당 블로그(http://ggamu.com/81)에서 제공하는 방식대로 database 자체에 timezone을 서울로 변경하였다.


하지만 그래도 계속해서 값이 UTC로 들어갔고 그래서 혹시 몰라 삽입하는 코드에 new Date('2018-10-18 11:11:11').toLocalString()를 설정해줬다.


하지만 그래도 역시나 ㅜㅜ 

그래서 sequelize 라이브러리 자체에 설정을 하는 부분이 있는지 싶어서 확이해봤는데, 설정 자체에 timezone을 설정하는 부분이 있었다.


그래서 sequelize 객체를 만들때 사용하는 option에 timezone옵션을 부여해줬다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "user": "root",
  "password": "test",
  "database": "oauth2",
  "options": {
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+09:00",
    "define": {
      "charset": "utf8mb4",
      "dialectOptions": {
        "collate": "utf8mb4_general_ci"
      }
    },
    "pool": {
      "min": 0,
      "max": 10,
      "idle": 10000,
      "acquire": 10000
    }
  }
}
cs


그랬더니 정상적으로 timezone에 맞게 입력되었다.

이런 타임존 문제 때문에 epoch_second를 삽입해서 자주 사용한다. 


바꿔서 진행하던지 해야겠다 ㅜ

댓글()
  1. 지나가는이 2019.07.01 20:11 댓글주소  수정/삭제  댓글쓰기

    덕분에 시간을 아낄 수 있었습니다. 감사합니다. ^^

node js에서 stream pipe 사용시 에러 처리 방법

web/node.js|2018. 11. 9. 22:28

node js에서 데이터를 stream을 사용하여 처리하고 pipe를 사용해서 계속해서 stream을 가지고 작업을 이어나갈 수 있다. 그런데 pipe를 통해서 작업을 진행하다 보니까 중간에 오류가 발생했을 때 try / catch 로는 정상적으로 처리하지 못하는 경우가 발생했다. 

나에 경우에는 에러가 발생했을 때 try / catch에서 잡히지 않아서 프로그램이 Unhandled Promise Rejections를 출력 하며 죽어버렸다.

그 예는 다음과 같이 request를 통해서 받은 이미지를 sharp 라이브러리를 통해서 이미지 크기를 변경하려고 할 때 발생했다.

1
try {
await request('https://image.toast.com/aaaaab/ticketlink/TKL_3/ion_main08061242.jpg').pipe(transformer).pipe(writeStream);
} catch (e) {
console.error(e);
}
cs


그래서 이를 처리하기 위해서 알아봤는데 각 파이프라인에서 발생하는 에러를 처리하기 위해서는 try/catch로만 잡을 수가 없다. 그래서 이를 해결하기 위해서 각 파이프 앞단에서 error 이벤트를 잡는 설정을 해줘야한다.


1
2
3
4
5
6
7
8
// 파일로 쓰기
await request('https://image.toast.com/aaaaab/ticketlink/TKL_3/ion_main08061242.jpg').on('error', function (e) {
  console.error(e);
}).pipe(transformer).on('error', function (e) {
  console.error(e);
}).pipe(writeStream).on('error', function (e) {
  console.error(e);
});
cs


하지만 이렇게만 하면 에러는 잡을 수 있어도 pipe에서 행이 걸리는 경우가 발생된다. 그래서 에러가 발생했을 때 행 걸리지 않고 다음 로직으로 정상적으로 처리되도록 하기 위해서는 this.emit('end')를 넣어줘야 한다.


1
2
3
4
5
6
7
8
9
10
11
// 파일로 쓰기
await request('https://image.toast.com/aaaaab/ticketlink/TKL_3/ion_main08061242.jpg').on('error', function (e) {
  console.error(e);
  this.emit('end');
}).pipe(transformer).on('error', function (e) {
  console.error(e);
  this.emit('end');
}).pipe(writeStream).on('error', function (e) {
  console.error(e);
  this.emit('end');
});
cs


참고

https://stackoverflow.com/questions/21771220/error-handling-with-node-js-streams


댓글()

Elasticsearch query string 조회시 parse exception 에러 처리

elasticsearch에서 query_string로 데이터 조회시에 쿼리문으로 ) 특수문자가 포함하여 조회했다. 하지만 다음과 같이 문제가 발생했다.


1
2
3
4
5
6
7
8
9
10
11
{
  "error": {
    "root_cause": [
      {
        "type": "parse_exception",
        "reason": "parse_exception: Encountered \" \")\" \") \"\" at line 1, column 11.\nWas expecting one of:\n    <EOF> \n    <AND> ...\n    <OR> ...\n    <NOT> ...\n    \"+\" ...\n    \"-\" ...\n    <BAREOPER> ...\n    \"(\" ...\n    \"*\" ...\n    \"^\" ...\n    <QUOTED> ...\n    <TERM> ...\n    <FUZZY_SLOP> ...\n    <PREFIXTERM> ...\n    <WILDTERM> ...\n    <REGEXPTERM> ...\n    \"[\" ...\n    \"{\" ...\n    <NUMBER> ...\n    "
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "phase": "query",
cs


확인해보니 + - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ / 포함된 문장을 query_string 통해서 조회하려고 하면 에러를 발생시킨다. 그래서 이를 해결하기 위해서 위에 reserved character들이 들어간 단어는 \\를 붙여주어야 한다.


이를 위한 자바스크립트는 다음과 같다.

1
2
3
async escapeReservedCharacter(query) {
  return query.replace(/([!*+&|()<>[\]{}^~?:\-="/\\])/g, '\\$1');
}
cs


이를 해결해서 query_string을 사용하면 문제가 해결된다.


참고 : https://stackoverflow.com/questions/26431958/escaping-lucene-characters-using-javascript-regex




댓글()

node.js express에서 request 사용자 아이피 찾기

web/node.js|2018. 10. 15. 22:26

요청한 사용자의 Ip를 찾아서 로그를 남기거나 Ip 지역정보를 활용해서 geoIp를 찾아내거나 할 때 request를 요청한 사용자의 IP 주소가 필요하다.


Spring에서는 간단하게 HttpServletRequest에서 getHeader의 X-FORWARDED-FOR에 있는 정보를 가져오거나 getRemoteAddr()을 통해 가져올 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 * 주문요청.
 *
 * @param req the req
 * @return the response entity
*/
@PostMapping(value = "/order")
public ResponseEntity<?> order(@Valid @RequestBody OrderRequestDto req, HttpServletRequest request) {
    String ip = request.getHeader("X-FORWARDED-FOR");
    if (ip == null)
        ip = request.getRemoteAddr();
 
    return ResponseEntity.ok(orderService.order(req));
}
cs


우선 헤더에서 X-FORWARDED-FOR에서 왜 아이피 정보를 찾는건가? 대부분의 사용자 요청이 오면 사용자 요청은 Load Balance등을 통해서 오게되기 때문에 원천 아이피를 찾을 수 없기 때무에 X-FORWARDED-FOR에 원천 아이피를 넣어서 전송한다.

결론은 XFF는 HTTP Header 중 하나로 HTPP Server에 요청한 Client의 IP를 식별하기 위한 표준이다.

참고 : http://blog.plura.io/?p=6597


그럼 node.js에서는 어떻게 가져와야 하나? 아주 간단하다.

1
const ip = req.headers['x-forwarded-for'||  req.connection.remoteAddress;
cs


그리고 만약 로컬에서 ::1로 사용자 IP가 출력되는 경우가 있다. ::1은 IpV6에서 로컬 호스트를 의미한다. 그래서 express 서버를 생성할 때 IPV4를 사용하도록 설정하면 된다.


댓글()

Javascript에서 epoch second 구하기

web/javaScript|2018. 10. 13. 10:07

epoch second 는 유닉스 시간을 나타내고 Epoch 시간 이라고 한다. 이를 자바스크립트로 구하는 방법을 알아보자.

1
Math.floor(new Date('2018-03-11') / 1000)
cs


다시 Date 값으로 돌리는 것도 어렵지 않다.

1
new Date(1520726400 * 1000)
cs



댓글()

Javascript promise에 대해 알아보자.

web/javaScript|2018. 10. 6. 23:02

기존에 ajax와 같은 비동기 요청이 종료가 되고 특정한 작업을 수행하고 싶을경우 콜백함수를 설정하여 진행했었다.

1
2
3
4
5
6
7
8
9
10
11
  Common.sendAjax({
    url: Common.getFullPath('user/cert/check'),
    param: { 'otp' : $otpNum.val(), 'userId' : $joinEmail.val() },
    type: 'POST',
    success: (e) => {
      // 성공 시 발생할 콜백함수
    },
    failed: () => {
      // 실패시 발생할 콜백함수
    }
  });
cs


이런 비동기 프로그래밍은 기존 동기식 프로그래밍 보다 작업을 요청하고 다른 작업을 할 수 있는 장점이 있다. 하지만 이는 그 유명한 콜백 지옥을 만들 수 가 있다. 

아래 보면 이런 콜백 지옥을 경험을 다들 해봤을거다.  실제로 이렇게 콜백지옥이 발생한 경우가 굉장히 많다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  Common.sendAjax({
    url: Common.getFullPath('user/cert/check'),
    param: { 'otp' : $otpNum.val(), 'userId' : $joinEmail.val() },
    type: 'POST',
    success: (e) => {
      // 성공 시 발생할 함수
      Common.sendAjax({
        success:(e) => {
          Common.sendAjax({     
            /**
                콜백지옥     
           
            */ 
          });
        }
      });
    },
    failed: () => {
      // 실패시 발생할 함수
    }
  });
cs


Promise를 적용해서 비동기 프로그래밍 진행하기.

promise 객체를 만들고 동작을 수행한 후 성공하면 resolve, 실패할 경우에 reject 메소드를 실행시킨다. resolve 메소드를 실행할 경우 promise 상태는 Fulfilled 상태가 된다. 그리고 reject 메소드가 실행되면 Rejected 상태가 된다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Promise 
 
'use strict';
 
const test = module.exports;
 
test.proTest = (isSucess) => {
  return new Promise((resolve, reject) => {
    isSucess ? resolve('re1') : reject(new Error('r2'));
  });
};
 
 
 
 
// 테스트 코드
 
'use strict';
 
const promiseTest = require('../../lib/libraryTest/promise-test');
const assert = require('assert');
const chai = require('chai');
const should = chai.should;
const expect = chai.expect;
 
describe('promise 테스트', () => {
  it('resolve 테스트', async () => {
    try {
      let resolveTest = await promiseTest.proTest(true);
 
      assert(resolveTest == 're1');
    } catch (e) {
      should.not.exist(e);
    }
 
  });
 
  it('reject 테스트', async () => {
    try {
      let resolveTest = await promiseTest.proTest(false);
    } catch (e) {
      console.log(e);
      expect(e).to.exist;
    }
  });
 
});
cs


Promise Chaining 

프로미스를 이용해서 콜백 지옥 대신에 프로미스를 연결해서 연속된 동작을 진행할 수 있다. 하지만 이런 프로미스 체이닝도 문제가 있는게 에러 발생시에 catch로 받을 수 있지만 어느 프로미스에서 발생한 에러인지를 알기가 어렵다는 문제가 있다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'use strict';
 
const test = module.exports;
 
test.proTest = (isSucess) => {
  return new Promise((resolve, reject) => {
    isSucess ? resolve('re1') : reject(new Error('r2'));
  }).then((result) => {
    return result + 'babo';
  }).then((result) => {
    return result + 'Hi!';
  }).catch((err) => {
    return err;
  });
};
cs



댓글()

node.js에서 aws s3 스토리지에 이미지 저장하기

web/node.js|2018. 10. 6. 01:55

AWS에서 제공하는 S3 스토리지는 다양한 파일을 bucket에 보관할 수 있다. 자세한 내용은 생활코딩 강의 참고하면 좋다. https://opentutorials.org/course/608/3006


그럼 우선 aws sdk를 설치하여야 한다.

1
npm i aws-sdk --save
cs


그리고 AWS IAM에서 생성한 사용자가 있어야 한다. 사용자는 S3에 대한 권한을 가지고 있어야 한다.


사용자를 생성하고 권한을 부여하는 기능은 어렵지 않기때문에 검색해서 적용하면 된다.

그리고 해당 사용자를 생성하면 csv 파일로 secretkey를 받을 수 있다. 이를 AWS S3에 접근하여 사용하기 위해서 사용된다.




기본 정보가 담긴 config.json 생성

우선 부여 받은 사용자 accessKeyId와 secretAccessKey 그리고 지역정보가 담긴 config.json 파일을 만든다.

1
2
3
4
5
{
  "accessKeyId""<accessKeyId>",
  "secretAccessKey""<secretAccessKey>",
  "region""ap-northeast-2"
}
cs


그리고 aws-sdk 라이브러리를 로드하면서 위에 생성한 config.json 파일을 추가해준다. 그리고 S3 객체의 경우 로드한 aws-sdk에서 new와 함께 s3() 메소드를 실행하여 만들 수 있다.

1
2
3
4
5
6
'use strict';
 
const AWS = require('aws-sdk');
const path = require('path');
AWS.config.loadFromPath(path.join(__dirname, 'config.json'));
const S3 = new AWS.S3();
cs


그리고 이미지 파일을 업로드 하기위해서 제공하는 메소드인 upload에는 bucket 이름, 파일의 고유 키, 파일이 담긴 Body, Body의 contentType 정보가 필요하다. 나는 이미지를 올리려고 하기 때문에 contentType은 image/jpg로 하였다.

1
2
3
4
5
   const params = {};
    params.Key = `image/${md5(url)}.jpg`;
    params.Bucket = bucket;
    params.Body = await request(url);
    params.contentType = 'image/jpg';
cs

생성된 최종 코드는 다음과 같다.

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
'use strict';
 
const AWS = require('aws-sdk');
const path = require('path');
AWS.config.loadFromPath(path.join(__dirname, 'config.json'));
const S3 = new AWS.S3();
const md5 = require('md5');
const request = require('request-promise');
const bucket = 's3-buckets';
 
class AwsS3 {
 
  async upload(url)  {
    const params = {};
    params.Key = `image/${md5(url)}.jpg`;
    params.Bucket = bucket;
    params.Body = await request(url);
    params.contentType = 'image/jpg';
 
    S3.upload(params, function (err, data) {
      console.log(err);
      console.log(data);
    });
  }
 
}
 
module.exports = new AwsS3();
 
cs


그리고 테스트 코드를 작성하여 동작 시켜보면 정상적으로 파일이 올라간것을 확인 할 수 있다.

1
2
3
4
5
6
7
8
9
'use strict';
 
const s3 = require('../../lib/s3');
 
describe('s3 test', () => {
  it('upload', async () => {
    await s3.upload('http://ticketimage.interpark.com/Play/image/large/18/18009670_p.gif');
  });
});
cs


 이런 문제가 발생하면 config.json에 기재한 키 정보를 다시한번 확인해봐야한다.
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
31
32
33
34
35
{ InvalidAccessKeyId: The AWS Access Key Id you provided does not exist in our records.
    at Request.extractError (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/services/s3.js:580:35)
    at Request.callListeners (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/sequential_executor.js:109:20)
    at Request.emit (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/sequential_executor.js:81:10)
    at Request.emit (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/request.js:683:14)
    at Request.transition (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/request.js:685:12)
    at Request.callListeners (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/sequential_executor.js:119:18)
    at Request.emit (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/sequential_executor.js:81:10)
    at Request.emit (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/request.js:683:14)
    at Request.transition (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/request.js:685:12)
    at Request.callListeners (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/sequential_executor.js:119:18)
    at callNextListener (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/sequential_executor.js:99:12)
    at IncomingMessage.onEnd (/Users/wedul/Documents/repository/nodejs/node_modules/aws-sdk/lib/event_listeners.js:294:13)
    at emitNone (events.js:111:20)
    at IncomingMessage.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1064:12)
    at _combinedTickCallback (internal/process/next_tick.js:139:11)
    at process._tickDomainCallback (internal/process/next_tick.js:219:9)
  message: 'The AWS Access Key Id you provided does not exist in our records.',
  code: 'InvalidAccessKeyId',
  region: null,
  time: 2018-10-01T15:53:23.570Z,
  cfId: undefined,
  statusCode: 403,
  retryable: false,
  retryDelay: 32.0943451721504 }
 
cs


참고 URL
https://www.npmjs.com/package/aws-sdk
https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/s3-example-creating-buckets.html

https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/loading-node-credentials-json-file.html

댓글()