aggregate
mongoDB에서 집계(aggregation)라는 것부터 무엇인지 알아보겠다. 집계는 방대한 양의 문서를 여러 단계를 거쳐서 처리하는 방법을 말한다. 여러 단계를 거친다 표현했는데 이를 조금 더 디테일하게 말하자면 파이프라인을 거친다고도 표현한다. 파이프라인에서는 문서를 필터링하고, 정렬, 그룹화, 모양 변경 등을 진행해 문서를 수정하게 된다.
집계 데이터를 얻는 방법은 다양하다. 기본적으로 find() 쿼리를 사용하게 된다면 빠르게 원하는 데이터를 조회할 수 있다. 하지만 find() 쿼리의 단점은 그 범위가 제한된다는 것이다.
파이프라인
집계 파이프라인은 어떻게 동작할까?
[
$match:
$group:
$sort:
$limit:
$skip:
...
]
사실 단계에는 정해진 규약같은 것은 없다고 생각한다. 다만 기본적으로 $match, $group 정도의 파이프라인은 디폴트로 깔고 들어가야 한다. (하지만 실제로 쿼리를 입력해보면 $match만 입력해도 잘 나온다.) $match는 작업해야할 문서를 필터링하고, $group은 집계 작업을 수행한다. 문서 상으로는 이렇게 적혀있는데 도저히 봐도 이해가 안갈 수 있다. 그럴 땐, 직접 쿼리를 입력해보자.
쿼리 삽입
내 블로그에서는 더미데이터를 삽입하지 않을 것이다. 더미데이터가 필요할 때만 이 단락을 참고한다.
db.collectionName.insert([
{
country : 'Spain',
city : 'Salamanca',
name : 'USAL',
location : {
type : 'Point',
coordinates : [ -5.6722512,17, 40.9607792 ]
},
students : [
{ year : 2014, number : 24774 },
{ year : 2015, number : 23166 },
{ year : 2016, number : 21913 },
{ year : 2017, number : 21715 }
]
},
{
country : 'Spain',
city : 'Salamanca',
name : 'UPSA',
location : {
type : 'Point',
coordinates : [ -5.6691191,17, 40.9631732 ]
},
students : [
{ year : 2014, number : 4788 },
{ year : 2015, number : 4821 },
{ year : 2016, number : 6550 },
{ year : 2017, number : 6125 }
]
}
])
예제는 다음과 같다. 위에서 언급했지만 이 더미데이터로 집계하지 않을 것을 다시 언급해두겠다.
공공데이터에서 뽑아보기
사내에서 사용하는 공공데이터는 국가에서 제공해주는 오픈소스이기 때문에 크롤링되어 저장되있는 데이터를 가지고 예시를 들겠다. 공공데이터는 대한민국 내에 있는 병원과 보건소 등의 데이터이다. 보건소 데이터를 find() 쿼리를 사용해보면 다음과 같이 얻을 수 있다.
db.collection.find({'clCdNm': '보건소'})
다음과 같은 쿼리를 입력하면 아래의 객체 데이터를 얻을 수 있다.
{
"_id": {
"$oid": ""
},
"addr": "",
"clCd": 71,
"clCdNm": "보건소",
"cmdcGdrCnt": ,
"cmdcIntnCnt": ,
"cmdcResdntCnt": ,
"cmdcSdrCnt": ,
"detyGdrCnt": ,
"detyIntnCnt": ,
"detyResdntCnt": ,
"detySdrCnt": ,
"drTotCnt": ,
"emdongNm": "",
"estbDd": ,
"hospUrl": "",
"mdeptGdrCnt": ,
"mdeptIntnCnt": ,
"mdeptResdntCnt": ,
"mdeptSdrCnt": ,
"pnursCnt": ,
"postNo": ,
"sgguCd": ,
"sgguCdNm": "",
"sidoCd": ,
"sidoCdNm": "",
"telno": "",
"XPos": ,
"YPos": ,
"yadmNm": "",
"ykiho": ""
}
실제로는 보건소가 아닌 병원, 의원 등 여러 데이터들이 존재한다. 집계 함수(aggregate)를 사용해서 추출할 데이터는 보건소이면서 그에 해당하는 보건소의 이름, 전화번호, 주소, ykiho의 데이터들을 조회해보겠다.
다시 돌아가서 find()쿼리를 사용했을 때는 RDB에서 WHERE 조건처럼 그에 해당하는 데이터만 뽑아올 수 있었다. 하지만 여기서 어떤 데이터만을 가져올 것인지에는 제약이 있다. 이럴 때 aggregate를 사용한다.
db.collection.aggregate([
{ $match: {clCdNm: {$regex: '보건소'}}}
)
이렇게만 실행해보면 위에서 find() 쿼리를 사용한 것처럼 데이터를 필터링해올 수 있다. 이것이 $match 단계의 역할이다.
db.collection.aggregate([
{ $match: {clCdNm: {$regex: '보건소'}}},
{ $group: {'name': '$yadmNm', 'tel': '$telno', 'address': '$addr', 'ykiho': '$ykiho'}}
)
이제 그 다음 단계인 $group을 설정해준다. $match를 통해 필터링한 데이터 중 name, tel, address, ykiho만을 가져와서 보여줄 수 있다.
{
"_id": {
"$oid": ""
},
"name": "",
"tel": "",
"address": "",
"ykiho": ""
}
그러면 이런 식으로 원하는 데이터만을 가져올 수 있는 것이다.
정리
find() 쿼리를 사용해 쉽게 데이터를 조회할 수 있지만 집계 데이터로써는 부적합할 경우가 많다. 그럴 때는 aggregate 라는 쿼리를 사용해 파이프라인을 거쳐 집계 데이터를 손쉽게 얻을 수 있게 된다.
참고
https://studio3t.com/ko/knowledge-base/articles/mongodb-aggregation-framework/
MongoDB 집계: 예제 및 연습이 포함된 튜토리얼 | Studio 3T
MongoDB 집계 파이프라인을 마스터하세요. 가장 중요한 집계 단계를 사용하여 쿼리 예제를 따라 하고 실력을 테스트해 보세요!
studio3t.com