본문 바로가기
혼자 공부하는 것들/javascript

[mongoDB, JavaScript] 시간복잡도를 줄여보자! join이 안된다고??

by applepick 2021. 6. 2.
반응형

회사에서 기존 서비스 기능들을 기능 개선을 하고 있다.

mongoDB를 사용하는데 단점이…. join이 안된다…. ㅠㅠ 

예를 들어 a class가 있는데 이 class에서 하나의 필드가 포인터로 b class의 기본키나 다른 키를 가리키고 있다고 하면

mysql이나 다른 곳에는 join기능이 있어 한번 쿼리로 b class의 객체까지 담아서 가져올 수 있지만 mongoDB에서는 그게 안된다…

그렇다면 어떻게 해야 할까?

어쩔 수 없다! 쿼리를 두 번해서 join을 직접 코드로 넣어줘야 한다!

두 번 쿼리 하는 거는 Promise chaining을 해서 비동기로 가져오면 된다.(이 것도 나중에 시간이 되면 정리해야겠다.)

ex) 
aList = [
	{
	 _id: "dasdas",
         name: "name$asldasd", ->b class의 _id를 가르키는 포인터
         startDate: "200606"
	}
    ...
];

bList = [
	{
	 _id: "asldasd",
         phone : "010-0000-0000"
	}
    ...
];

두 번 쿼리 한 결과가  aList와 bList의 배열 안에 이뤄져있다고 하자.(네이밍이 아주아주 중요하지만 여기서는 간단하게 설명하기 위해 대충 지었습니다.)

aList.forEach(a => {
    a.name = a.name.split("$")[1];
    bList.forEach(b => {
        if (a.name == b._id) {
            a.name = b;
        }
    });
});

이런 식으로 join을 할 수 있다. a의 name 필드의 값이 b의 기본키를 포인터로 가리키고 있을 때 포인터를 split 해서 문자열에서 지우고,  bList를 forEach문을 돌려 선택 삽입을 하였다.  이때 시간 복잡도는 n^2이 된다.

하지만 이것을 2n으로 줄일 수 있다! 

bList name값으로 mapping 해줘서 key값으로 만든 다음 배열에서찾아갈 수 있도록 만 들으면된다.

let list = {};
for (let b of bList) {
    list[b._id] = b;
}
aList.forEach(a => {
    if (a.name.split("$")[1] in list) {
        a.name = list[a.name.split("$")[1]];
    }
});

이런 식으로 구현하면 된다. 여기서는 bList를 mapping 해주는 for문의 시간 복잡도 n과 aList안에 넣어주는 n을 해서 시간 복잡도를 2n으로 줄일 수 있다.

최종적으로 결과는 

이런 식으로 aList의 name field안에 bList가 잘 들어간 것을 볼 수가 있다.(join 기능) 비록 Duration 차이는별로 없겠지만이것이 하나하나쌓이다 보면 몇 초 차이가 나기 때문에 항상 내가 작성한 코드에 의구심을 들고 효율적인 방법을 찾아야 한다고 생각한다.

반응형

댓글