[Day49] 2022-04-07(목) MongoDB4 - Aggregation, PyMongo Setting - 김서연 강사님
[1] Aggregation
- Aggregation framework와 mapreduce가 제공
- RDBMS의 group by의 개념
- 집계작업이 단순한 경우에 mapreduce보다는 aggregation framework를 사용
- input으로 사용된 document를 처리하고 처리 결과로 ouput document를 생성하고
생성된 ouput document를 또 다른 명령어의 input document로 활용
=> 이를 파이프라인(Pipeline)이라 한다.
- 파이프라인으로 집계를 처리하며 이 처리 명령을 배열로 나타낸다.
1. Aggregation Operator
- $match : where절, having절과 같은 개념
- $group : group by
- $sort : order by
- $sum : 총합(총합을 계산할 필드 명시), 총 갯수(1을 정의)
- $avg : 평균
- $max : 최댓값
- $min : 최솟값
2. 형식
- db.collection.aggregate( aggregation operator 이용한 명령어 )
- 여러 개를 사용하는 경우 배열로 표현
- ([
{$match: {조건...}},
{$group: { _id: "$집계할 기준이 되는 필드명", 출력될 필드명: {집계함수: "$집계할 필드명이나 값"}}}
})
3. Aggregation 기본 예제
1) 조건 없는 예제
① addr별 인원수
- db.score.aggregate( [ { $group: { myaddr: "$addr", num: {$sum: 1} } } ] ) - X
- db.score.aggregate( [ { $group: { _id: "$addr", num: {$sum: 1} } } ] ) - O
=> SQL : SELECT addr _id, count(*) num FROM score GROUP BY addr
② dept 별 인원수
- db.score.aggregate( [ { $group: { _id: "$dept", num: { $sum: 1 } } } ] )
③ dept 별 java 점수의 평균
- db.score.aggregate( [ { $group: { _id: "$dept", java_avg: { $avg: "$java" } } } ] )
④ addr 별 servlet 점수의 합계
- db.score.aggregate( [ { $group: { _id: "$addr", servlet_sum: { $sum: "$servlet" } } } ] )
2) 조건 적용 예제 ($match 사용)
- java가 80점 이상인 사람들이 부서별로 몇 명인지 구하기
- db.score.aggregate( [
{ $match: { java: { $gte: 80 } } },
{ $group: { _id: "$dept", num: { $sum: 1 } } }
] )
=> SQL : SELECT dept _id, count(*) num FROM score WHERE java >= 80 GROUP BY dept
3) 정렬 적용 예제 ($sort 사용)
- 2)의 예제를 인원수에 대해서 오름차순으로 정렬
- db.score.aggregate( [
{ $match: { java: { $gte: 80 } } },
{ $group: { _id: "$dept", num: { $sum: 1 } } },
{ $sort: { num: 1 } }
] )
=> SQL : SELECT dept _id, count(*) num FROM score WHERE java >= 80 GROUP BY dept ORDER BY num ASC
※ 배열 필드로 조건 사용 QUERY
- 조건 중에 배열 필드가 있는 경우 QUERY 예제
1) favorites 의 city 배열에 서울 또는 인천이 존재하는 모든 document 조회
db.test.find( { "favorites.city": { $in: [ "서울", "인천" ] } } )
2) favorites 의 city 배열에 서울과 인천이 존재하고, java점수가 90점 이상인 데이터 조회
db.test.find( { $and: [ { "favorites.city": { $in: [ " 서울", "인천" ] } }, { java: { $gte: 90 } } ] } )
3) 쉬리 영화를 보거나 부서가 인사인 document
db.test.find( { $or: [ { "favorites.movie": "쉬리" }, { dept: "인사" } ] } )
4) city가 부산 또는 울산이면서 헬로카봇을 본 document 조회
db.test.find( { $and : [ { "favorites.city" : { $in: [ "부산", "울산" ] } }, { "favorites.movie": "헬로카봇" } ] } )
4) 배열 필드 조건 사용 예제
test 컬렉션을 이용해서 작업하세요
1. dept가 인사인 document의 servlet 평균 구하기
db.test.aggregate( [
{ $match: { dept: "인사" } },
{ $group: { _id: "$dept", servlet_avg: { $avg: "$servlet" } } }
] )
2. java가 80점이 넘는 사람들의 부서별로 몇 명인지 구하기
db.test.aggregate( [
{ $match: { java: { $gte: 80 } } },
{ $group: { _id: "$dept", num: { $sum: 1 } } }
] )
3. 2번 결과를 인원수 데이터를 내림차순으로 정렬해 보세요.
- java점수의 평균도 함께 출력하기
db.test.aggregate( [
{ $match: { java: { $gte: 80 } } },
{ $group: { _id: "$dept", num: { $sum: 1 }, java_avg: { $avg: "$java" } } },
{ $sort: { num: -1 } }
] )
4. 앞에서 작업한 결과에 null인 document를 제외하세요
- 앞에서의 작업 : db.score.aggregate( [ { $group: { _id: "$addr", num: {$sum: 1} } } ] )
db.score.aggregate( [
{ $match: { addr: { $exists: true } } },
{ $group: { _id: "$addr", num: {$sum: 1} } }
] )
5. 다음과 같은 조건을 만족하는 document의 부서별 인원수를 구하세요
- 서울, 울산에 거주한 경험이 있고 헬로카봇을 본 적이 있다.
- java 점수가 80점 이상이다.
- 위 두 개의 조건을 모두 만족해야 한다.
db.test.aggregate( [
{ $match: { $and: [
{ "favorites.city": { $in: [ "서울", "울산" ] } },
{ "favorites.movie": "헬로카봇" },
{ java: { $gte: 80 } } ]
} },
{ $group : { _id: "$dept", num: { $sum: 1 } } }
] )
6. 다음과 같은 조건을 만족하는 document 들의 부서별로 java의 평균을 구하세요
- 인천에 거주한 경험이 있거나 겨울왕국을 본 경험이 있다.
- java 점수가 90점 이상이다.
- 위 두 개의 조건은 둘 중에 하나만 만족하면 됩니다.
db.test.aggregate( [
{ $match: { $or: [
{ "favorites.city": "인천" },
{ "favorites.movie": "겨울왕국" },
{ java: { $gte: 90 } }
] } },
{ $group: { _id: "$dept", java_avg: { $avg: "$java"} } }
] )
[2] PyMongo - Python 과 MongoDB 연동
1. Setting
1) PyMongo 라이브러리 설치
2) import pymongo
import pymongo
3) local host 로 접속을 위한 객체 생성
- 객체만 생성하는 것으로 접속이 된 상태는 아님
- 매번 객체를 활용할 때 접속되는 것
# mongodb 서버에 접속해서 작업할 수 있도록 MongoClient 객체 생성
client = pymongo.MongoClient("mongodb://127.0.0.1:27017")
# client = pymongo.MongoClient("mongodb://localhost:27017")
4) 접속 확인 및 데이터베이스 리스트 확인
# database 접속
print(client.list_database_names()) # db 목록 확인
5) 외부 접속 허용
- 문제는 로컬 호스트 말고 외부에서 IP를 통해 들어오는 것이 불가능하므로 이에 대한 셋팅 필요
① 기존의 dbpath로 설정된 경로의 폴더를 별도의 폴더(mongodb) 로 이동
② mongodb 폴더에 log 폴더 생성
③ mongodb 폴더에 텍스트 파일 생성하고 파일명을 .txt까지 지우고 mongod.cfg 로 변경 (cfg는 설정 파일)
④ mongod.cfg 를 텍스트 파일로 열어서 아래 내용을 입력
- 여기서 bind_ip=0.0.0.0 이 바로 외부 접속을 허용하는 부분 (기본 셋팅은 127.0.0.1 로 되어 있었을 것)
dbpath=C:\2022_iot\mongodb\data
logpath=C:\2022_iot\mongodb\log\mongod.log
logappend=true
bind_ip=0.0.0.0
port=27017
⑤ cmd창 > mongod --config C\2022_iot\mongodb\mongod.cfg
⑥ log 폴더에 mongod.log 가 생성되며, 실행시켜 보면, 로그가 기록되어 있는 것을 확인할 수 있다.
⑥ 이제 python에서 IP를 직접 입력해도 접속 되는 것을 확인할 수 있다. (XXX.XXX.XXX.XXX 에 IP 입력)
import pymongo
# mongodb 서버에 접속해서 작업할 수 있도록 MongoClient 객체 생성
client = pymongo.MongoClient("mongodb://XXX.XXX.XXX.XXX:27017")
# database 접속
print(client.list_database_names()) # db 목록 확인
2. Mongo Shell 에서 사용하던 기능들 사용하기
1) show dbs
- client객체.list_database_names( )
print(client.list_database_names()) # db 목록 출력
2) show collections
- db객체.list_collection_names( )
db = client.get_database("sample") # sample db 저장
print(db.list_collection_names()) # sample db 내의 collection 출력
3) collection에서 document 하나 가져와서 출력
- 방법1 : db객체.collection명.find_one( ) => 자동완성 기능X
- 방법2 : collection객체.find_one( ) => 자동완성 기능O
myscore = db["score"] # sample db 내의 score collection 저장
# sample 데이터베이스의 score 컬렉션에서 데이터 조회하기 -1
result = db.score.find_one()
print(result)
# sample 데이터베이스의 score 컬렉션에서 데이터 조회하기 -2
result2 = myscore.find_one()
print(result2)
4) 그 외 기능들은 내일 이어서...
3. 번거로운 서버 접속 기능을 class로 정의
MyMongo.py
import pymongo
# MyMongo 클래스를 조건에 맞게 작성하세요
# - MyMongo 생성자 정의하기 : 매개변수는 ip와 port를 전달받아 클래스변수를 초기화할 수 있도록 처리
# - connect 메소드를 정의
# db명과 collection명을 매개변수로
# mongodb 서버에 접속
# db 데이터베이스에 접속
# collection 컬렉션을 리턴하도록 작성
class MyMongo:
def __init__(self, ip, port):
self.ip = ip
self.port = port
def connect(self, db_name, collection_name):
client = pymongo.MongoClient("mongodb://"+self.ip+":"+self.port)
db = client.get_database(db_name)
# collection = db[collection_name]
collection = db.get_collection(collection_name)
return collection
MyMongoTest.py
from MyMongo import MyMongo
# MyMongoTest python파일을 작성하고 MyMongo 클래스의 connect 메소드를 활용하여
# document 한 개 조회해서 결과를 출력할 수 있도록 작성
my_mongo = MyMongo("XXX.XXX.XXX.XXX", "27017")
score = my_mongo.connect("sample", "score")
result = score.find_one()
print(result)
- 끝 -