MongoDB 설치(docker-compose) 및 Python Client 예제
NoSQL
- Not Only SQL -> 관계형 데이터베이스가 아닌 데이터베이스 (Not RDBMS)
- 대표적인 특징
- 스키마가 따로 없기 때문에 데이터 구조를 유연하게 설정할 수 있음
- 독립적 데이터 모델 설계 덕분에 여러 서버에 분산시키기 편리함
- 데이터의 일관성, 정합성 등이 필요한 경우 부적합 (데이터 중복 발생 가능)
- SQL, NoSQL 비교
이번 포스팅에선, NoSQL 중 Document 기반 DB에 해당하는 MongoDB를 docker-compose를 통해 설치 해보고, python client로 간단한 CRUD 예제를 진행해보겠습니다.
Docker image Pull
- MongoDB 이미지 pull (docker-hub 참고)
docker pull mongo
docker-compose ( MongoDB & Mongo-express )
- docker-compose.yml 파일 작성 (docker-hub 참고, mongo-express는 시각화 도구 중 하나)
version: '3.1'
services:
mongodb:
image: mongo
restart: always
ports:
- 27017:27017
volumes:
- ./mongodb:/data/db
environment:
- MONGO_INITDB_ROOT_USERNAME={아이디}
- MONGO_INITDB_ROOT_PASSWORD={비밀번호}
- MONGO_INITDB_DATABASE={시작DB 이름}
mongo-express:
image: mongo-express
restart: always
ports:
- {사용할 포트}:8081
environment:
- ME_CONFIG_MONGODB_SERVER=mongodb
- ME_CONFIG_MONGODB_PORT=27017
- ME_CONFIG_MONGODB_ADMINUSERNAME={아이디}
- ME_CONFIG_MONGODB_ADMINPASSWORD={비밀번호}
- ME_CONFIG_BASICAUTH_USERNAME={아이디}
- ME_CONFIG_BASICAUTH_PASSWORD={비밀번호}
depends_on:
- mongodb
- 컨테이너 실행
docker-compose up -d
- Mongo-express 접속 화면
python client CRUD 예제
- 라이브러리 import
from pymongo import MongoClient
from pprint import pprint
- client 연결
client = MongoClient(host='MongoDB host url', port=27017, username='아이디', password='비밀번호')
- Database, Collection, Document 생성
- MongoDB는 RDBMS처럼 empty Database를 생성할 수 없다. 할 필요가 없음 (schema-less)
- Collection과 document가 생성될 때, Database 목록에서 해당 Database를 조회할 수 있음
# Database
epozen = client.epozen
# Collection
team_dt = epozen.team_dt
# Document ('_id' 지정 안 하면 알아서 고유 id 부여)
team_dt.insert_one({
# '_id': 1,
'name': 'member_1', # str
'age': 26, # int
'hobby': ['math'], # list
'pet': {'dog': 'happy'}, # dict
'score': 60.0 # float
})
- Database 목록
client.list_database_names()
- Collection 목록
epozen.list_collection_names()
- Document 하나 삽입
team_dt.insert_one({
'name': 'member_2',
'age': 27,
'hobby': ['soccer', 'music', 'math'],
'pet': {'dog': 'happy', 'cat': 'kitty'},
'score': 80.0
})
- Document 여러개 삽입
team_dt.insert_many([
{
'name': 'member_3',
'age': 28,
'hobby': ['baseball', 'music'],
'pet': {'cat': 'mike'},
'score': 75.5
},
{
'name': 'member_4',
'age': 29,
'hobby': [],
'pet': {'dog': 'alice'},
'score': 90.0
},
{
'name': 'member_5',
'age': 30,
'hobby': ['music'],
'pet': {},
'score': 100.0
},
])
- Document 하나 조회, 조건 없이 수행 시, 맨 처음 삽입한 Document 가져옴
pprint(team_dt.find_one())
- Document 전체 조회
for doc in team_dt.find():
pprint(doc)
- Document 조회, 조건 입력
for doc in team_dt.find({'age': 27}):
pprint(doc.get('age'))
- Document 조회, advanced query ($gt -> greater -> ~보다 큰)
for doc in team_dt.find({'score': {'$gt': 80}}):
pprint(doc.get('score'))
- Document 조회, 정규표현식 (이름이 3으로 끝나는), 문자열 데이터에만 적용 가능
for doc in team_dt.find({'name': {'$regex': '3$'}}):
pprint(doc.get('name'))
- Document 정렬 (오름차순)
for doc in team_dt.find().sort('score', 1):
pprint(doc.get('score'))
- Document 정렬 (내림차순)
for doc in team_dt.find().sort('score', -1):
pprint(doc.get('score'))
- Document 하나 수정
team_dt.update_one({'name': 'member_3'}, {'$set': {'name': 'test_3'}})
pprint(team_dt.find_one({'name': 'test_3'}))
- Document 여러개 수정
team_dt.update_many({'name': {'$regex': '^member'}},
{'$set': {'name': 'test_name'}})
for doc in team_dt.find():
pprint(doc)
- 결과 반환 수 제한 limit()
for doc in team_dt.find().limit(3):
pprint(doc)
- Document 하나 삭제
team_dt.delete_one({'age': 30})
for doc in team_dt.find():
pprint(doc)
- Document 여러개 삭제
team_dt.delete_many({'score': {'$lt': 80}})
for doc in team_dt.find():
pprint(doc)
- Collection 내 모든 Document 삭제
team_dt.delete_many({})
for doc in team_dt.find():
pprint(doc)
- Collection 삭제
team_dt.drop()
pprint(epozen.list_collection_names())
정리
- api를 기반으로 CRUD가 가능해서 보다 직관적으로 데이터를 다룰 수 있다.
- 데이터가 정합성이나 일관성 등을 띄어야 하는 경우, 부적합 할 수 있다. (ex. 병원 환자 데이터, 은행 시스템 등)
- 반면, 데이터 구조가 불분명하고, 데이터 변경 및 확장 발생 가능성이 있는 경우에는 적합할 수 있다. (ex. 공정 내 여러 종류의 센서 데이터, 대규모 로그 데이터 등)
추후에는 MongoDB의 최대 장점이라 할 수 있는 분산 처리 환경도 구성해 볼 예정이다.