목차

반응형
module.exports.version_list = function () {
return new Promise(function (resolve, reject) {
var sql = "SELECT * FROM STATUS_VERSION";
db.connectDatabase().query(sql, function (err, result) {
if (err) console.log(err);
resolve(result);
});
});
}

이런식으로 프로미스를 이용한 쿼리 실행을 정의하였고


version.version_list.then(function (version_doc) {
res.end(JSON.stringify(version_doc[0]));
})

이렇게 실행을 하였으나 업데이트 쿼리나  실행해도 쿼리값이 제대로 반영이 안되는 문제가 있었다.


함수를 호출할때 ()를 안붙여서 그런것이었는데

아무래도 함수에 대한 결과값이 정해져서 그런것같다.

version.version_list().then(function (result) {
console.log(result);
res.render('admin/version_control', {result: result[0]})
})

이렇게 바꾸니까 잘된다.


간단한 문제였지만 쿼리 실행자체는 문제가 없어서 눈치채기가 힘들었다.

반응형
반응형

https://support.cloud.engineyard.com/hc/en-us/articles/205408088-Access-Your-Database-Remotely-Through-an-SSH-Tunnel

tunnel ssh경우 쿼리를 모듈화해서 짜기가 곤란해서 난항을 겪고있었는데 매우 꿀팁이다.


cmd에서 ssh가 작동한다는 가정하에 진행한다.


ssh tunnel은 아래와 같이 ec2와 rds 2개의 서버가 있다고 쳤을때 rds는 외부에서 접근이 안되지만 ec2내부에서는 rds로 접근이 가능하다고 쳤을때 내 pc에서 ssh를 우회하여 rds로 접근하는 것이라고 생각하면 된다. (찾아보지는 않았음 뇌피셜임 ㅈㅅ)

 VPC에 있는 DB 인스턴스에 다른 VPC에 있는 EC2 인스턴스가 액세스


ssh -L 3307:rds주소:3306 아이디@ec2주소

상단의 사이트에 가보면 이처럼 명령어를 로컬 cmd(윈도우 기준)에다가 쳐야한다.


3307은 3306은 뭐 겹친다는데 그냥 따라했다.

ec2주소는 aws ec2로 접속하는 주소를 적는다.

아이디는 rds로 접속하는 계정명을 적는다.(흠 근데 rds와 ec2 접속 계정명이 같아서 rds 계정 아이디를 적는 것인지 확실치 않다. 설명에는 rds 계정명을 적으라고 나와있다.)

rds 주소는 aws에서 생성한 rds 주소를 적는다.


이렇게 적어서 실행을 해보면 잘된다. 안되면 설정상에 문제가 있는 것이다.



로컬 cmd에서 위 명령어를 실행했을때 모습 -> 일반적인 ssh 접속과 똑같은 결과


이후 로컬 node 앱에서의 db 주소를 127.0.0.1 이라고 놓고 작업을 하면 잘 작동한다.

var mysql      = require('mysql');
var connection = mysql.createConnection({
host : '127.0.0.1',
user : '아이디',
password : '비밀번호',
database: 'db명',
port: 3307
});

connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}

console.log('connected as id ' + connection.threadId);
});

로컬 node 앱에서 mysql로 접속하는 코드는 위와 같다. 위의 코드를 실행해보면


잘 접속한다.


이제 mongodb를 mysql로 교체작업하러간다 에효...

반응형
반응형

내 질문

안녕하세요 저는 커뮤니티 어플리케이션의 백엔드 부분을 구현하고 있습니다.

서버는 nodejs와 mongodb에 mongoose를 사용하고있습니다.

다름아니라 mongodb가 단일 컬렉션에 대한 질의는 정말 편하고 빠르다는 것을 장점으로 생각하여 어플리케이션의

db를 mongodb로 선택하게 되었고 서버스크립트의 작성이 거의 끝난 상태입니다.

하지만 커뮤니티라면 거의 필수적으로 있는 게시물 컬렉션, 게시물에 대한 댓글 컬렉션의 조인을 구현하면서

두가지 의문이 생겼습니다.


제가 인터넷에서 찾아본 결과 'mongodb는 rdbms가 아니기 때문에 rdbms의 핵심인 PK와 FK에 의한 참조 관계를

 피해야한다' 라는 의견이 대다수였습니다.

하지만 정말 단순한 커뮤니티에서도 게시물과 댓글에 대한 조인은 피할 수 없다고 생각하는데 도대체

mongodb를 사용한 커뮤니티는 게시물과 댓글에 대한 관계를 어떤 방식으로 구현했는지 궁금합니다.


또한 여러개의 컬렉션을 조인하기 위해서 aggregation의 lookup, pipeline을 사용하거나

두번의 중첩된 find문을 통하여 javascript로 push하는 방식으로 조인 기능을 구현하였습니다.

아래 사이트의 소스코드가 제가 말씀드린 두가지 방식입니다. 참고하시면 좋을 것 같습니다.

https://stackoverflow.com/questions/50545105/are-there-any-better-ways-joining-two-collections-in-mongodb-in-nodejs

rdbms라면 join문을 사용하면 되는 간단한 상황이지만

mongodb에서는 이렇게 복잡한 쿼리문과 코드로밖에 구현을 못하는 것인지 여쭤보고싶습니다.

감사합니다.



답변

일단 몽고디비(Nosql)는 최대한 조이닝을 안하는 방향으로 사용합니다. 도큐먼트의 고유 값으로 최대한 쿼리를 하는게 몽고디비의 핵심입니다. 너무 헤비한 데이터가 아닌이상 참조관계보다 서브도큐먼트를 이용하는게 제가 봤을땐 더 좋을 것 같네요. 조이닝이 많아지는 기능의 DB를 설계하는데 NoSql을 선택했다는 것 자체부터 DB선택에 에러가 있다고 생각하구요.. 조이닝이 많이 필요한 구조면 당연히 관계형 DB를 사용하는게 맞죠 그게 아니라면 MongoDB 서브도큐먼트를 자유자제로 다룰줄 알아야 합니다. 서브도큐먼트도 제어하기가 꽤 복잡하기에 디비에 자신이 크게없거나 공부에 시간을 많이 투자를 못한다하면 일반적으로 mysql이 낫겠네여


Q1. mongodb를 사용한 커뮤니티는 게시물과 댓글에 대한 관계를 어떤 방식으로 구현했는지 궁금합니다.


A1. 현재 단쿠키는 게시글에 대한 모든 댓글, 좋아요, 싫어요 등을 서브도큐먼트로 처리했습니다.



Q2. 저희코드에서 어그리게이션이나 중첩 find문이 속도 저하의 원인인지 궁금합니다.


A2. DB상에서 연산은 서버의 연산보다 2~3배 정도 느리기 때문에 DB상에서 연산은 최대한으로 줄여야합니다. 어그리게이션은 사실 서비스 보다 디비 분석을 위한 연산이라 CRUD 서비스에서는 속도가 매우 느리고 과부하가 걸릴 수 있죠.



Q3. 서브도큐먼트를 쓰면 만약 좋아요 개수를 하나 늘리는데 게시판 전체 컬렉션을 참조해야되고 또 한 도큐먼트에 너무 여러가지 정보가 담겨서 관리면에서 좀 복잡해지지 않을까요? 단쿠키는 왜 몽고디비를 선택했나요?


A3. 노드JS랑 궁합이 잘 맞으니까요ㅠ 그래서 이제 DB 인덱싱을해야 쿼리 효울성이 높아지긴 하는데 인덱싱 어그리게이션 서브도큐먼트 맵리듀스 등 .. 을 종현이형이나 제가 잘 쓴다고 자신을 하고 개발했지만서도 아직도 단쿠키도 디비 구조에 문제가 많거든요 ㅠ 최근에 저희도 mysql로 롤백할까 생각도 가끔해요 디비라는건 한번 구조가 잡히고 서비스 된다면 바꾸기가 힘드니깐요 ㅜ



Q4. 추후에 쇼핑에 결제기능까지 추가할건데 그렇게되면 몽고디비를 쓰는데있어서 또 문제가생길까요?


A4. 결제기능을 어떻게 추가하실지는 모르겠지만 계좌이체방식이면 오히려 JSON형식으로 관리하는 몽고디비가 편할수도있겠네요 하나의 도큐먼트에 모든 정보가 직관적으로 들어가있기에 json이 보기편하고 관계형이 오히려 불편할수도있어요



Q5. 혹시 몽고디비 사용할때 생긴 문제점이 뭐가있었나요? 저희도 고려해야하는 부분이 있을까 싶어서요


A5. 댓글을 서브도큐먼트로 처리하는데 댓글을 검색할때 서브도큐먼트를 다 통과하는 알고리즘으로 검색을 해야하는데 

기존처럼 관계형 DB였다면 댓글 테이블만 찾으면 될 것을 서브도큐먼트니깐 더 연산이 오래걸리더라고요.. 그래서 아직 댓글검색 기능은 보류중입니다.


기존 mongodb로 작업되어있던것 전부다 mysql로 갈아타기위해서 작업 준비중이다.

질문에 친절하게 답변해주신분은 현재 단국대학교 사이트 개발자분이시다. (감사합니다.)

http://www.dankookie.com/

에효...

반응형
반응형

****주의****

만약 당신이 몽고DB를 3.4에서 3.6으로 업데이트를 할 것이라면

업데이트 하기전에 db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )명령어를

친다면 매우 수월하게 작업 할 수 있음.



몽고DB 3.4에서는 aggregate에서 let과 pipeline을 통해 join에  2개 이상의 조건을 달 수 없다.

그렇게 어쩔수 없지 매우우우 귀찮지만 3.4에서 3.6으로 업데이트를 하기로 했다.

lookup aggregate 관련 문서

https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/



잠깐 맛탱이가 갔는지 쓰지도 않는 노트북의 윈도우 몽고 db 3.6을 설치했다.

https://www.mongodb.com/download-center?&_ga=2.120737096.1701553497.1524490974-915795993.1521988095#production



오 근데 윈도우에서 sql studio처럼 몽고db를 프로그램을 통하여 관리할 수 있는

gui 관리 프로그램이 있다는 것을 깨달았다. 나름 개이득본듯?



일단 아래 명령어로 모듈을 설정하는 곳으로 이동

cd /etc/yum.repos.d 



몽고db repo 생성

sudo vi mongodb-org-3.6.repo

[mongodb-org-3.6]name=MongoDB Repositorybaseurl=https://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.6/x86_64/gpgcheck=1enabled=1gpgkey=https://www.mongodb.org/static/pgp/server-3.6.asc



이후

sudo yum install -y mongodb-org-3.6



그리고 나서 몽고db를 키려니까

** IMPORTANT: UPGRADE PROBLEM: The data files need to be fully upgraded to version 3.4 before attempting an upgrade to 3.6; see http://dochub.mongodb.org/core/3.6-upgrade-fcv for more details.

메시지가 뜨면서 실행이 안된다.



아니 진작말하지 개빡치게 3.6으로 설치해놨더니

다시 몽고db 인스턴스를 켜서 db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } ) 명령어를 치라고 한다.

근데 몽고db 인스턴스를 키려면 3.4버전으로밖에 킬 수가 없다.

그래 그러면 다시 다운그레이드를 해야지



몽고db를 다운그레이드를 하는 방법

몽고db 인스턴스를 킨다.

db.adminCommand( { setFeatureCompatibilityVersion: "3.4" } ) 명령어를 친다.



아니 도랐나 이때 ㄹㅇ 개빡쳐서(지금보니까 공식 레퍼런스에서는 미리 저 명령어를 쳐두라고 나와있음 근데 귀차나서 걍 설치과정만 읽은듯 ㅉㅉ)

이때부터 아무생각없이 그냥 다 날려버리고 재설치했다.




아래는 매우 빡친 순간에서 만난 에러 코드다.


mongodb shutting down with code:62

/data/db 폴더 삭제 => 데이터 날라가는데 아무 생각없이 걍 날려버림;;


shutting down with code:100

sudo mongod


WARNING: This server is bound to localhost.

2018-04-24T00:29:30.434+0900 I CONTROL  [initandlisten] **          Remote systems will be unable to connect to this server.

--bind_ip_all


lock 관련 오류

mongod --repair

반응형
반응형

상황은 이와 같다. 몽고디비를 몽구스로 사용하는데 최초등록한 key값을 나중에 지워야하는 경우가 발생하였다.

하지만 스키마에서 unique값만 바꾼다고해서 기존의 collection에 들어가 있던 키 설정이 지워지지 않기때문에 db로 들어가서 key를 삭제해줘야한다.


이 같은 상황에서는 주로 아래의 에러가 뜬다.

 MongoError: E11000 duplicate key error index car.wheel.$index_1 dup key: { : 3 }

=> 현재 index라는 key값이 중복되어서 문제가 발생한다고 보면 된다.


일단 해당 db로 들어가서 collection에 대한 인덱스(키라고 생각하면 편할듯)의 값들을 보자.

db.collection.getIndexes() 명령어를 친다.


내가 mongoose를 사용하여 key값으로 지정한 필드는 wheel_name, index임을 알 수있다. (_id는 기본 key값임 무시)

나같은 상황은 원래 index를 키값으로 사용했으나 이를 없애고 wheel_name을 인덱스로만 사용하고자 한다.

따라서 index라는 키 설정을 지워야한다.

위 사진의 "key":{"index":1} 의 key 필드에 대한 value값을 주목하자 해당 값으로 지워야한다.



db.collection.dropIndex({key에 해당하는 value값}) 명령어를 치면 index가 잘 지워진다.



몽고db reference

반응형
반응형

게시판 같은 경우 mysql이나 oracle에서는 rownum을 이용하여 페이징을 쉽게 처리하였으나

몽고db, 몽구스는 해당 기능이 딱히 없는듯 하다.

그래서 아래와 같이 페이징 처리를 해주는 함수를 만들어봤다


필요한 파라미터는 몽구스 find함수의 결과물, pageIndex, pageUnit이다.

pageUnit은 한 페이지에 들어가는 게시물 개수를 뜻하고 pageIndex는 불러올 페이지의 개수를 뜻한다.

만약에 게시판의 맨처음 페이지로 진입하면 pageIndex는 1이어야한다.



bbs.find(query, function (err, result) {
if (err)
return res.end(err);
if (!req.body.pageIndex)
req.body.pageIndex = "";
if (!req.body.pageUnit)
req.body.pageUnit = "";
res.end(JSON.stringify(paging(result, req.body.pageIndex, req.body.pageUnit)));
});




var paging = function (bbs, pageIndex, pageUnit) {

var length = bbs.length;
//bbs -> 게시물 조회결과, pageIndex -> 현재 페이지, pageUnit -> 페이지당 게시물 단위수
if (pageIndex == '' && pageUnit == '')
return bbs;
else {
if (pageIndex > length / pageUnit) {
console.log("error no such page index " + pageIndex + "<=" + length + "/" + pageUnit);
return null;
}
var startIndex = (pageIndex - 1) * pageUnit;
var endIndex = pageIndex * pageUnit;
var data = [];
for (var i = startIndex; i < endIndex; i++) {
data.push(bbs[i]);
}
return data;
}
}


오 근데 인텔리제이 개오지네 그냥 소스복붙만해도 이렇게나옴 

반응형
반응형

for(var i=0;i<5;i++)

{

function asd(i) {

  console.log(i+3);

}

}

을 하면 분명 3 4 5 6 7 이 나와야 하지만

7 7 7 7 7이 나온다.


정말 골치아픈 문제였다.

분명 작동은 하는데 반복문 안의 함수가 맨 마지막 i값으로만 처리가 되버린다.

처음에는 어이가 없었음.


아마도 meanstack의 동기처리 때문에 그런듯 하다. (동기처리가 정말 밉더라)

http://apple77y.tistory.com/11


해결법으로는 3가지를 찾았음.


1. 반복문 안의 함수를 반복문 밖에서 선언한뒤에 parameter를 사용하여 정상적으로 수행.

근데 내가 만든 기능이 find안에 find를 또쓰는거라서 너무 복잡해버리게되어서 2번으로 해본뒤에 2번으로 쓰기로함.

function asd(num) {

  return (num+3);

}

이런식으로 만든뒤에

for(var i=0;i<5;i++)

{

asd(i);

}

대충 이런식?


2. With ({ n : i }) { ... }를 이용하여 정상적으로 수행.

function test() {

  for (var i = 0; i < 5; i++) {

       with ({ n: i }) {

      function asd() {

console.log(n+3);

}

    }

  }

}

.이런느낌? 개인적으로 2번보다 깔쌈한것같음.

3. Promise 기능을 사용하여 수행.

먼가 고급스러운 해결방법같지만 너무 어려워보여서 싫었음.


http://stackoverflow.com/questions/1451009/javascript-infamous-loop-issue

반응형
반응형


UserModel.find({}, function (err, users) {

    return res.end(JSON.stringify(users));

}

이와 같은 형태로

Mongoose에서 찾은 json데이터를 넘길때 throw new TypeError('first argument must be a string or Buffer'); 에러가 뜬다.


이 에러는 Mongoose 객체가 Json 객체와는 별도이기 때문에 JSON.stringify 함수가 작동을 하지 않는 것이다.

따라서 find에 .lean()을 붙여주어 Json 객체로 바꿔준다.


UserModel.find().lean().exec(function (err, users) {

    return res.end(JSON.stringify(users));

}


http://stackoverflow.com/questions/9952649/convert-mongoose-docs-to-json



반응형
반응형

var User = mongoose.model('user', dataSchema);

라고 하면 User 몽구스 모델이 user 콜렉션을 참조하는 것이 아니라 users를 참조함.


따라서 스키마를 만들때 콜렉션의 이름을 지정해줘야함

var schema = new Schema({ name: String }, { collection: 'actor' });

이와같은 형태로 스키마를 만들때 콜렉션 이름을 지정해주면 제대로 불러옴.


http://stackoverflow.com/questions/10547118/why-does-mongoose-always-add-an-s-to-the-end-of-my-collection-name


반응형
반응형

원리


1. html에서 post방식으로 서버에 신호를 보냄.


<script>
app.controller('myCtrl', function($scope, $http) {    
    $scope.liked = function() {
        $http.post('/').
        success(function(data) {
            $scope.test=data; // post에 대한 서버로부터의 응답을 html의 test라는 것에 넣어줌
        }).error(function() {
        })
    };
});
</script>

컨트롤러는 알아서 설정하고

아무곳에 ng-click="liked()" 집어넣음.

이렇게 해놓으면 liked함수가 실행되면서 위의 스크립트가 작동함.




2. 서버에서 올바른 신호를 받으면 db 관련 데이터 처리

db는 mongoose로했음.

일단 먼저 몽구스 모듈 불러오고 연결함.

가장 중요한것 은 모델, 스키마를 잘 설정하는것

스키마 설정 예시

var userSchema = new mongoose.Schema({

like: {type:Number},

info:{type:String}

});

이거 타입을 잘맞춰줘야함.


이것만 잘 설정해도 거의 모든 에러가 다 사라짐. (모델, 스키마를 잘못 설정해서 에러가 엄청많이 떴음)

에러는 안나지만 세이브가 안되는 에러 해결됨

업데이트할때 like 가 하나 더생겨버리고 NAN 생기는 에러 사라짐

[ { _id: '576cd52ed5ea2827f765a5a0', like: 0, info: 'like' },  like: NaN ]

TypeError: User.save is not a function 에러도 사라짐





3. 서버에서 처리한 데이터를 html로 다시 보냄

res.end(documents[0].like+""); 

이러면 like넘버가 알아서 data변수로 html로 넘어감



4. html에서는 post에 대한 응답으로 받은 데이터를 다시 html에 나타내줌

$scope.test=data;

반응형