'nodejs'에 해당되는 글 18건
sequelize에서 조인 시 left join이 되지 않을 때 처리하는 방법
sequelize에서 조인을 할때는 include를 사용해서 다음과 같이 한다.
1 2 3 4 5 6 | await This.User.findOne({ attributes: ['id', ['name', 'userName']], include: [ { model: this.Dept} ] }); | cs |
물론 기존에 Model을 define할 때 연관관계를 설정을 해놓은 상태여야 하고 이렇게 할 경우에 나는 left join이 아니라 inner join으로 다음과 같이 되었다.
SELECT id, name as userName FROM User u inner join Dept d on u.userId = d.userId;
그래서 검색해서 알아보다보니 required 옵션을 부여하게 되면 정상적으로 left join이 된다고 알게되었다.
그래서 붙이니 정상적으로 되었다.
1 2 3 4 5 6 | await This.User.findOne({ attributes: ['id', ['name', 'userName']], include: [ { model: this.Dept, required: false} ] }); | cs |
별개로 조인을 하려고 하는데 계속 서브쿼리가 만들어진다면 subquery:false 옵션을 주면 문제를 해결 할 수 있다.
'web > node.js' 카테고리의 다른 글
Nginx, Apache 그리고 node.js 성능 관련 잡다한 정리 (0) | 2019.02.07 |
---|---|
sequelize에서 상황에 따라 조인 테이블을 변경하는 방법 - alias (0) | 2018.12.19 |
sequelize에서 조인 시 left join이 되지 않을 때 처리하는 방법 (0) | 2018.12.19 |
sequelize에서 alias 사용하여 검색하는 방법 (0) | 2018.12.19 |
sequelize 사용시 테이블 이름 변동없이 고정 Alias 사용방법 (0) | 2018.12.19 |
sequelize에서 timezone 설정 추가 (0) | 2018.11.26 |
sequelize 사용시 테이블 이름 변동없이 고정 Alias 사용방법
sequelize는 마찬가지로 ORM을 사용하다보니 직접적으로 쿼리를 사용하는 것보다 정확하게 알지못하면 역시 개발속도도 늦어지고 문제가 많아지는 단점이 있다.
이번에는 sequelize를 사용하는데 조인할 때 테이블 이름이 갑자기 User에서 Users로 바뀌는 이슈가 발생했다.
이 이슈를 해결하기 위해서 sequelize Document를 검색했고 거기서 freeTableName 옵션을 발견했다.
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 | const Bar = sequelize.define('bar', { /* bla */ }, { // don't add the timestamp attributes (updatedAt, createdAt) timestamps: false, // don't delete database entries but set the newly added attribute deletedAt // to the current date (when deletion was done). paranoid will only work if // timestamps are enabled paranoid: true, // don't use camelcase for automatically added attributes but underscore style // so updatedAt will be updated_at underscored: true, // disable the modification of table names; By default, sequelize will automatically // transform all passed model names (first parameter of define) into plural. // if you don't want that, set the following freezeTableName: true, // define the table's name tableName: 'my_very_custom_table_name', // Enable optimistic locking. When enabled, sequelize will add a version count attribute // to the model and throw an OptimisticLockingError error when stale instances are saved. // Set to true or a string with the attribute name you want to use to enable. version: true }) | cs |
설명 그대로 이름이 plural로 바뀌는 것을 방지 하고 singular로 사용할 수 있게 해주는 옵션이다.
'web > node.js' 카테고리의 다른 글
sequelize에서 조인 시 left join이 되지 않을 때 처리하는 방법 (0) | 2018.12.19 |
---|---|
sequelize에서 alias 사용하여 검색하는 방법 (0) | 2018.12.19 |
sequelize 사용시 테이블 이름 변동없이 고정 Alias 사용방법 (0) | 2018.12.19 |
sequelize에서 timezone 설정 추가 (0) | 2018.11.26 |
node.js oauth2 server 만들기 (1) | 2018.11.25 |
Promise에서 Unhandled Rejection 설명 (0) | 2018.11.09 |
node js에서 stream pipe 사용시 에러 처리 방법
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
'web > node.js' 카테고리의 다른 글
node.js oauth2 server 만들기 (1) | 2018.11.25 |
---|---|
Promise에서 Unhandled Rejection 설명 (0) | 2018.11.09 |
node js에서 stream pipe 사용시 에러 처리 방법 (0) | 2018.11.09 |
node.js에서 sharp를 사용해서 이미지 크기 변경하기 (0) | 2018.10.22 |
maxmind의 geoLite2를 이용해서 접속한 사용자의 지역정보 가져오기 (0) | 2018.10.16 |
node.js express에서 request 사용자 아이피 찾기 (0) | 2018.10.15 |
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
'데이터베이스 > Elasticsearch' 카테고리의 다른 글
Elasticsearch에서 search_after 기능 사용하여 조회하기 (0) | 2018.11.17 |
---|---|
Elasticsearch에서 Full text queries와 Term level queries 정리 (0) | 2018.11.01 |
Elasticsearch query string 조회시 parse exception 에러 처리 (0) | 2018.10.31 |
Elasticsearch에서 Paging시 max_result_window 초과시 조회가 안되는 이슈 (0) | 2018.10.13 |
Elasticsearch 6.4 기본 한글 형태소 분석기 노리 (nori) 설명 및 사전 추가하기 (0) | 2018.10.13 |
엘라스틱 서치 (elasticsearch) fielddata (0) | 2018.10.06 |
maxmind의 geoLite2를 이용해서 접속한 사용자의 지역정보 가져오기
서비스를 운영하다보면 사용자 아이피에 따라 장소에 맞는 상품을 추천해줘야 할 때가 있다.
그럴때 사용하는게 geoIp인데 이런 서비스를 제공하는 회사는 대표적으로 maxmind, db-ip, ipstack, ip2location 등이 존재한다.
그 중에 무료로 사용하기에 geoLite2가 좋다. geoLite2는 62%가 일치하고 geoIp2는 66% 일치한 정보를 제공한다. 그래서 무료로 사용할 수 있는 geoLite2를 사용해보자.
데이터베이스 다운로드
먼저 지역정보를 보관하고 있는 데이터베이스를 다운받아야 한다. 데이터베이스는 csv와 mmDB를 제공한다.
링크 : https://dev.maxmind.com/geoip/geoip2/geolite2/
mmDB에서 데이터를 확인하기 어렵기 때문에 csv 파일에서 제공하는 정보를 보자. 우리가 필요한 정보는 사용자가 접속한 city (도시)정보가 필요한데 그 필드가 geoname_id로 되어 있다. 그 geoname_id는 지역에 고유 아이디로 이 아이디에 맞는 city 정보를 찾는 방법은 아래 주소를 통해 xml 형태로 받아 볼 수 있다. username 값은 회원가입을 통해 등록 할 수있다.
1 | http://ws.geonames.org/get?geonameId=${geoname_id}&style=full&username=${userName} | cs |
그럼 node.js에서 이 데이터베이스와 사용자 ip를 사용하여 city 정보를 추출하는 방법을 확인해보자.
우선 아래 주소에서 maxmind npm을 다운로드 받는다.
https://www.npmjs.com/package/maxmind
그리고 maxmind 라이브러리를 사용해서 데이터베이스를 로드하고 ip를 사용하여 지오로케이션 정보를 조회 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 'use strict'; const maxmind = require('maxmind'); const path = require('path'); class MaxMindService { getIp(userIp) { const cityLookUp = maxmind.openSync(path.join(__dirname, './db/GeoLite2-City.mmdb')); const city = cityLookUp.get(userIp); return city; } }; module.exports = new MaxMindService(); | cs |
테스트 코드를 만들어서 결과를 확인해보자.
1 2 3 4 5 6 7 8 9 10 11 | 'use strict'; const geoIp = require('../../lib/maxMind'); describe('geo IP', function () { it('아이피 정보로 지역정보 찾아보기', () => { console.log(geoIp.getIp('121.131.27x.1xx')); }); }); | cs |
결과를 보면 ip에 맞는 위치정보가 출력된다.
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 | { city: { geoname_id: 1841277, names: { en: 'Mapo-gu' } }, continent: { code: 'AS', geoname_id: 6255147, names: { de: 'Asien', en: 'Asia', es: 'Asia', fr: 'Asie', ja: 'アジア', 'pt-BR': 'Ásia', ru: 'Азия', 'zh-CN': '亚洲' } }, country: { geoname_id: 1835841, iso_code: 'KR', names: { de: 'Südkorea', en: 'Republic of Korea', es: 'Corea del Sur', fr: 'Corée du Sud', ja: '大韓民国', 'pt-BR': 'Coreia do Sul', ru: 'Южная Корея', 'zh-CN': '大韩民国' } }, location: { accuracy_radius: 10, latitude: 37.5544, longitude: 126.9093, time_zone: 'Asia/Seoul' }, registered_country: { geoname_id: 1835841, iso_code: 'KR', names: { de: 'Südkorea', en: 'Republic of Korea', es: 'Corea del Sur', fr: 'Corée du Sud', ja: '大韓民国', 'pt-BR': 'Coreia do Sul', ru: 'Южная Корея', 'zh-CN': '大韩民国' } }, subdivisions: [ { geoname_id: 1835847, iso_code: '11', names: [Object] } ] } Process finished with exit code 0 | cs |
'web > node.js' 카테고리의 다른 글
node js에서 stream pipe 사용시 에러 처리 방법 (0) | 2018.11.09 |
---|---|
node.js에서 sharp를 사용해서 이미지 크기 변경하기 (0) | 2018.10.22 |
maxmind의 geoLite2를 이용해서 접속한 사용자의 지역정보 가져오기 (0) | 2018.10.16 |
node.js express에서 request 사용자 아이피 찾기 (0) | 2018.10.15 |
node.js에서 aws s3 스토리지에 이미지 저장하기 (0) | 2018.10.06 |
swagger api 보안 oauth2 설명 (0) | 2018.10.06 |