데이터베이스 NoSQL 심화 (mongoDB) - 실제 예제로 익히는 aggregation

5. 실제 예제로 익히는 aggregation

5.1. 실제 예제1: 1000만 이상의 state만 가져오기

  • SQL구문으로 작성해보기
    zip 컬렉션 - {'_id': '01001', 'city': 'AGAWAM', 'loc': [-72.622739, 42.070206], 'pop': 15338, 'state': 'MA'}
SQL(zip을 테이블이라고 생각) : SELECT state, SUM(pop) FROM zip GROUP BY state HAVING SUM(pop) > 10000000
  • GROUP BY 는 $group, WHERE 는 $match 를 사용할 수 있음
  • GROUP BY 에 조건을 거는 HAVING 절도 $match 로 사용할 수 있음
result = db.zip.aggregate([
    {'$group' : {'_id' : '$state', 'total_pop' : {'$sum' : '$pop'}}},
    {'$limit': 5}
])
for record in result:
    print(record)
{'_id': 'CA', 'total_pop': 29754890}
{'_id': 'MT', 'total_pop': 798948}
{'_id': 'MS', 'total_pop': 2573216}
{'_id': 'FL', 'total_pop': 12686644}
{'_id': 'AR', 'total_pop': 2350725}
출력 fields
- '_id' : '$field' --> SQL에서 GROUP BY field.
- total_pop : a calculated field that contains the total population of each state.
  - $sum operator : Add the population field (pop) for each state.

SQL과 비교해보자.
- SQL: SELECT state, SUM(pop) FROM zip GROUP BY state  
- mongodb aggregate: db.zip.aggregate([ {'$group' : {'_id' : '$state', 'total_pop' : {'$sum' : '$pop'}}} ])
# total_pop 만 출력하되 5개만 출력하기
result = db.zip.aggregate([
    {'$group' : {'_id' : '$state', 'total_pop' : {'$sum' : '$pop'} } },
    {'$project' : {'_id' : 0, 'total_pop' : 1} },
    {'$limit' : 5 }
])
for record in result:
    print(record)
{'total_pop': 29754890}
{'total_pop': 798948}
{'total_pop': 2573216}
{'total_pop': 12686644}
{'total_pop': 2350725}
result = db.zip.aggregate([
    {'$match' : {'pop' : {'$gte' : 100000}}},
    {'$limit' : 5 }
])
for record in result:
    print(record)
{'_id': '10021', 'city': 'NEW YORK', 'loc': [-73.958805, 40.768476], 'pop': 106564, 'state': 'NY'}
{'_id': '10025', 'city': 'NEW YORK', 'loc': [-73.968312, 40.797466], 'pop': 100027, 'state': 'NY'}
{'_id': '11226', 'city': 'BROOKLYN', 'loc': [-73.956985, 40.646694], 'pop': 111396, 'state': 'NY'}
{'_id': '60623', 'city': 'CHICAGO', 'loc': [-87.7157, 41.849015], 'pop': 112047, 'state': 'IL'}
출력 fields
- 전체 필드

SQL과 비교해보자.
- SQL: SELECT * FROM zip WHERE pop >= 100000  
- mongodb aggregate: db.zip.aggregate([ {'$match' : {'pop' : {'$gte' : 100000}}} ])
result = db.zip.aggregate([
    {'$group' : {'_id' : '$state', 'total_pop' : {'$sum' : '$pop'}}},
    {'$match' : {'total_pop' : {'$gte' : 10*1000*1000}}}
])
for record in result:
    print(record)
{'_id': 'CA', 'total_pop': 29754890}
{'_id': 'FL', 'total_pop': 12686644}
{'_id': 'PA', 'total_pop': 11881643}
{'_id': 'NY', 'total_pop': 17990402}
{'_id': 'OH', 'total_pop': 10846517}
{'_id': 'IL', 'total_pop': 11427576}
{'_id': 'TX', 'total_pop': 16984601}
- SQL1: SELECT state, SUM(pop) AS total_pop FROM zip GROUP BY state
- SQL2: SELECT * FROM zip WHERE pop >= 100000
- SQL1 + SQL2: SELECT state, SUM(pop) AS total_pop FROM zip HAVING pop >= 10000000

- mongodb aggregate:
result = db.zip.aggregate([
    {'$group' : {'_id' : '$state', 'total_pop' : {'$sum' : '$pop'}}},
    {'$match' : {'total_pop' : {'$gte' : 10*1000*1000}}}
])
이해하고 실습하기
1000만 이상의 state 의 총 인구를 state_pop 필드명으로 출력하고 _id는 출력하지 않기
result = db.zip.aggregate([
    {'$group' : {'_id' : '$state', 'state_pop' : {'$sum' : '$pop'}}},
    {'$match' : {'state_pop' : {'$gte' : 10*1000*1000}}},
    {'$project' : { '_id' : 0, 'state_pop': 1}}
])
for record in result:
    print(record)
{'state_pop': 29754890}
{'state_pop': 12686644}
{'state_pop': 11881643}
{'state_pop': 17990402}
{'state_pop': 10846517}
{'state_pop': 11427576}
{'state_pop': 16984601}

5.2. 실제 예제2: 1000만 이상의 state만 내림차순 정렬하여 3개만 가져오기

* $limit (LIMIT)

</pre>

  • group : 문자 그대로 grouping의 역할을 함
  • match : 조건에 맞는 documents만 필터링 함
  • sort : 차순에 맞게 정렬
  • limit : 개수 제한

1000만 이상의 state만 내림차순 정렬하기 ($sort)

result = db.zip.aggregate([
             {'$group' : {'_id' : '$state', 'total_pop' : {'$sum' : '$pop'}}}, 
             {'$match' : {'total_pop' : {'$gte' : 10 * 1000 * 1000}}},
             {'$sort' : {'total_pop' : -1}}
])
for record in result:
    print(record)
{'_id': 'CA', 'total_pop': 29754890}
{'_id': 'NY', 'total_pop': 17990402}
{'_id': 'TX', 'total_pop': 16984601}
{'_id': 'FL', 'total_pop': 12686644}
{'_id': 'PA', 'total_pop': 11881643}
{'_id': 'IL', 'total_pop': 11427576}
{'_id': 'OH', 'total_pop': 10846517}

1000만 이상의 state만 내림차순 정렬하고 5개만 가져오기 ($limit)

result = db.zip.aggregate([
             {'$group' : {'_id' : '$state', 'total_pop' : {'$sum' : '$pop'}}}, 
             {'$match' : {'total_pop' : {'$gte' : 10 * 1000 * 1000}}},
             {'$sort' : {'total_pop' : -1}},
             {'$limit' : 5}
])
for record in result:
    print(record)
{'_id': 'CA', 'total_pop': 29754890}
{'_id': 'NY', 'total_pop': 17990402}
{'_id': 'TX', 'total_pop': 16984601}
{'_id': 'FL', 'total_pop': 12686644}
{'_id': 'PA', 'total_pop': 11881643}

이해하고 실습하기
1000만 이상의 state 의 총 인구를 state_pop 필드명으로 출력하고 _id는 출력하지 않으며, 가장 많은 인구를 가진 3개만 출력하기 </font>

result = db.zip.aggregate([
    {'$group' : {'_id' : '$state', 'state_pop' : {'$sum' : '$pop'}}},
    {'$match' : {'state_pop' : {'$gte' : 10*1000*1000}}},
    {'$sort' : { 'state_pop' : -1 }},
    {'$project' : { '_id' : 0, 'state_pop': 1}},
    {'$limit' : 3}
])
for record in result:
    print(record)
{'state_pop': 29754890}
{'state_pop': 17990402}
{'state_pop': 16984601}