목차

반응형

내 질문

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

서버는 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;
}
}


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

반응형
반응형


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


반응형
반응형

몽고db와 몽구스는 엄연히 다르다

몽고db가 더욱 큰 개념인데

몽구스는 몽고db 드라이버라고 불린다.

몽고db 드라이버는 마치 몽고db의 플러그인같은 개념인데

몽구스라는 드라이버를 사용하게 되면서 얻는 이점은

db의 스키마를 설정할수있다.

다시 말하자면 몽구스를 사용하지 않는 몽고db는 스키마없이 데이터만 꾸역꾸역 집어넣기만 한다.


하지만 몽구스같은 드라이버를 사용하게되면 코드가 더욱 복잡해지며 데이터 처리가 복잡해지기 때문에 연산에서 에러가 날 가능성이 높아진다고 한다.


참고

http://stackoverflow.com/questions/28712248/difference-between-mongodb-and-mongoose

반응형
반응형

var mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/test');


cloud9에서는 위와같이하면 작동함.

반응형
반응형

sudo apt-get install -y mongodb-org

설치


$ mkdir data $ echo 'mongod --bind_ip=$IP --dbpath=data --nojournal --rest "$@"' > mongod $ chmod a+x mongod

설정


./mongod

로 mongodb 실행


새로운 터미널을 연뒤

$ mongo 쳐서 db 명령어 수행


후에 작동시킬때

Unclean shutdown detected. 가 뜨면


mongod --repair

친뒤에

다시 ./mongod 하면 구동 가능함


참고

https://community.c9.io/t/setting-up-mongodb/1717

반응형