몽고DB 소개
서버 시작
몽고DB 서버를 시작하기 위한 최소 파라미터는 다음과 같습니다:
--port: 기본값 27017--dbpath: 기본값 /data/db--logpath: 기본값 stdout로 출력
서버 시작 후 mongo 클라이언트로 연결하려면 mongo --port=27017을 사용합니다. --port는 기본값이므로 생략 가능합니다.
기본 개념
몽고DB는 Database, Collections, Documents 구조로 구성되며, 각각 데이터베이스, 컬렉션, 문서(키-값 쌍)에 해당합니다.
Database
use 데이터베이스명으로 데이터베이스를 전환합니다. 해당 데이터베이스가 존재하지 않으면 데이터 저장 시 자동으로 생성됩니다.cls로 mongo 콘솔 화면을 정리합니다.show dbs또는show databases로 모든 데이터베이스를 조회합니다.db로 현재 사용 중인 데이터베이스를 확인합니다.db.dropDatabase()로 현재 데이터베이스를 삭제합니다.
기본적으로 제공되는 세 가지 데이터베이스:
admin: root 데이터베이스로, 이 데이터베이스에 사용자를 추가하면 모든 권한이 상속됩니다.local: 복제 메커니즘에서 복제되지 않는 로컬 단일 서버용 데이터를 저장합니다.config: 샤딩 설정을 위해 내부적으로 사용되며 샤딩 관련 정보를 저장합니다.
Collections
- 데이터베이스를 전환 후
db.fruit.insert({name:"apple"})와 같이 데이터를 추가하면 존재하지 않는 Database와 Collection이 자동으로 생성됩니다. db.fruit.drop()로 컬렉션을 삭제합니다.show collections또는show tables로 모든 컬렉션을 조회합니다.db.createCollection(컬렉션명, [옵션])로 컬렉션을 생성합니다.
옵션 매개변수:
capped: 불리언 값. true로 설정하면 고정 크기 컬렉션이 생성되며, 최대 크기에 도달하면 가장 오래된 문서를 자동으로 덮어씁니다.size: 숫자 값. 고정 컬렉션의 최대 크기(바이트 단위)를 지정합니다.max: 숫자 값. 고정 컬렉션이 포함할 수 있는 문서의 최대 수를 지정합니다.
컬렉션 삭제: db.컬렉션명.drop()
기본 작업
insert - 문서 삽입
_id 필드를 지정하지 않으면 자동으로 생성되며, 지정된 경우 해당 _id를 사용합니다.
# 단일 문서 삽입 (새 버전 문법)
db.fruit.insertOne({name:"apple"})
# 여러 문서 삽입
db.fruit.insertMany([{name:"apple"}, {name:"pear"}, {name:"banana"}])
# insertMany 옵션
insertMany(
[{문서1}, {문서2}, {문서3}],
{
writeConcern: 1, // 쓰기 확인 정책, 1은 확인 요청, 0은 확인 요청 안 함
ordered: true // 순서대로 쓰기 여부, 기본값 true
}
)
# JavaScript for 루프를 사용한 삽입
for (let i = 0; i < 10; i++) {
db.test.insert({name:"item"+i, index:i})
}
find - 문서 조회
# 단일 조건 조회
db.test.find({age:18})
# 여러 조건 조회 (방법 1)
db.test.find({age:18, city:"seoul"})
# 여러 조건 조회 (방법 2)
db.test.find({$and:[{age:18}, {city:"seoul"}]})
# OR 조건 조회
db.test.find({$or:[{age:18}, {city:"seoul"}]})
# 비교 연산자 사용
db.test.find({"age":{$lt:50}}) // age < 50
db.test.find({"age":{$lte:50}}) // age <= 50
db.test.find({"age":{$ne:50}}) // age != 50
# 복합 조건
db.test.find({"age":{$gt:50}, $or:[{name:"user1"}, {name:"user2"}]})
# 하위 문서 조회
db.test.insertOne({name:"item", origin:{country:"korea", province:"seoul"}})
db.test.find({"origin.country":"korea"})
# 정규식을 사용한 패턴 매칭
db.test.find({"city":/^seoul/}) // seoul로 시작하는 도시
# 페이지네이션
db.test.find({name:/^item/}).sort({index:-1}).skip(1).limit(4) // 2페이지, 4개 항목
# 정렬
db.test.find({name:/^item/}).sort({index:-1}) // index 내림차순
db.test.find({name:/^item/}).sort({index:-1, name:1}) // index 내림차순, name 오름차순
# 문서 수 세기
db.컬렉션명.count() 또는 db.컬렉션명.find().count()
# 중복 제거
db.컬렉션명.find("필드").distinct()
# 배열 조회
db.test.insert([{name:"item1", tags:["red", "blue"]}, {name:"item2", tags:["green", "yellow"]}])
# 배열 요소 조회
db.test.find({tags:"red"}) // tags에 "red"가 있는 문서
db.test.find({$or:[{tags:"red"}, {tags:"blue"}]}) // tags에 "red" 또는 "blue"가 있는 문서
# 배열 내 객체 조회
db.test.insertOne({
title:"제목",
locations:[{"city":"seoul", "country":"korea"}, {"city:"busan", "country":"korea"}]
})
db.test.find({"locations":{$elemMatch:{"country":"korea", "city":"seoul"}}})
# 배열 길이로 조회
db.test.find({tags:{$size:2}}) // tags 배열이 2개인 문서
# 프로젝션 (필드 선택)
db.test.find({"locations":{$elemMatch:{"country":"korea", "city":"seoul"}}}, {"_id":0, "locations":1})
remove - 문서 삭제
db.컬렉션.remove(
쿼리, // 삭제 조건
{
justOne: boolean, // true인 경우 하나의 문서만 삭제
writeConcern: document // 예외 발생 수준
}
)
# 예제
db.test.remove({field:"value"}, {justOne:true}) // 조건에 맞는 첫 번째 문서만 삭제
db.test.remove({field:{$lt:5}}) // field가 5보다 작은 문서 삭제
db.test.remove({}) // 모든 문서 삭제
db.test.remove({_id:ObjectId("...")}) // 특정 ID 문서 삭제
update - 문서 업데이트
db.컬렉션.update(
쿼리, // 조회 조건
업데이트, // 업데이트할 내용
{
upsert: boolean, // true이고 문서가 없으면 삽입, 기본값 false
multi: boolean, // true이면 모든 일치 문서 업데이트, 기본값 false
writeConcern: document // 예외 발생 수준
}
)
# 주의: update는 기존 문서를 삭제하고 새 문서를 삽입합니다.
# 특정 필드만 업데이트하려면 $set 연산자 사용
db.test.updateOne({name:"item"}, {$set:{status:"active"}})
# updateOne: 일치하는 첫 번째 문서만 업데이트
# updateMany: 모든 일치 문서 업데이트
# 주요 업데이트 연산자
# $set/$unset: 필드 설정/제거
# $push/$pushAll/$pop: 배열에 요소 추가/제거
# $pull/$pullAll: 배열에서 요소 제거
# $addToSet: 배열에 중복 없이 요소 추가
인덱스
인덱스 생성
# 단일 필드 인덱스
db.컬렉션.createIndex({필드명:1}) // 1: 오름차순, -1: 내림차순
# 복합 인덱스
db.컬렉션.createIndex({필드명1:1, 필드명2:-1}) // 필드1 오름차순, 필드2 내림차순
# 인덱스 생성 옵션
db.컬렉션.createIndex({필드명:1}, {
background: true, // 백그라운드에서 인덱스 생성 (기본값: false)
unique: true, // 고유 인덱스 생성 (기본값: false)
name: "인덱스이름", // 인덱스 이름 지정
sparse: true, // null 값 필드는 인덱스에 포함하지 않음 (기본값: false)
expireAfterSeconds: 3600, // TTL(초) 설정
weights: {필드명: 100} // 가중치 설정
})
인덱스 관리
# 인덱스 조회
db.컬렉션.getIndexes()
# 인덱스 크기 확인
db.컬렉션.totalIndexSize()
# 인덱스 삭제
db.컬렉션.dropIndexes() // 모든 인덱스 삭제
db.컬렉션.dropIndex("인덱스이름") // 특정 인덱스 삭제
복합 인덱스
복합 인덱스는 여러 필드로 구성된 인덱스입니다. 몽고DB는 관계형 데이터베이스와 유사하게 왼쪽 포함 원칙을 따릅니다.
# 복합 인덱스 생성
db.컬렉션.createIndex({필드명1:1, 필드명2:1})
# 쿼리 시 인덱스 활용 예시
# 인덱스 필드 순서와 쿼리 필드 순서가 일치하거나,
# 인덱스의 왼쪽 필드들이 쿼리에 포함될 때 인덱스가 효과적으로 활용됩니다.
집계(Aggregation)
집계 연산자
$match: 문서 필터링
$eq, $gt, $gte, $lt, $lte: 비교 연산
$and, $or, $not: 논리 연산
$in: 포함 여부 확인
$project: 필드 선택/제거, 새 필드 생성
$group: 그룹화 및 집계 연산
$sum, $avg: 합계, 평균 계산
$push, $addToSet: 배열에 요소 추가
$first, $last: 첫 번째/마지막 문서 가져오기
$unwind: 배열 필드 확장
$bucket: 데이터 분류
aggregate() 메서드
# 문서 예시
db.컬렉션.insert([
{
title: '몽고DB 개요',
description: '몽고DB는 NoSQL 데이터베이스입니다',
author: '작가1',
tags: ['database', 'nosql'],
likes: 100
},
{
title: 'NoSQL 개요',
description: 'NoSQL 데이터베이스는 매우 빠릅니다',
author: '작가1',
tags: ['database', 'nosql'],
likes: 10
},
{
title: '다른 DB 개요',
description: '다른 종류의 NoSQL 데이터베이스',
author: '작가2',
tags: ['database', 'other'],
likes: 750
}
])
# 집합 예시: 작가별 좋아요 수 합계
db.컬렉션.aggregate([
{
$group: {
_id: "$author", // author 필드로 그룹화
total_likes: {$sum: "$likes"}, // likes 필드 합계
avg_likes: {$avg: "$likes"}, // likes 필드 평균
min_likes: {$min: "$likes"}, // 최소 likes
max_likes: {$max: "$likes"}, // 최대 likes
all_urls: {$push: "$url"} // 모든 URL 배열 생성
}
}
])
# 다른 집계 연산 예시
db.컬렉션.aggregate([
{$match: {likes: {$gt: 50}}}, // likes > 50인 문서만 선택
{$group: {_id: "$tags", count: {$sum: 1}}} // 태그별 문서 수 계산
])
레플리카 세트 설정
레플리카 세트는 데이터베이스의 고가용성을 제공합니다.
데이터 디렉토리 생성
mkdir -p /repl/data1
mkdir -p /repl/data2
mkdir -p /repl/data3
레플리카 세트 멤버 서버 시작
# 첫 번째 노드
mongod --port 27017 --dbpath /repl/data1 --bind_ip 0.0.0.0 --replset myreplica/localhost:27018,localhost:27019
# 두 번째 노드
mongod --port 27018 --dbpath /repl/data2 --bind_ip 0.0.0.0 --replset myreplica/localhost:27017,localhost:27019
# 세 번째 노드
mongod --port 27019 --dbpath /repl/data3 --bind_ip 0.0.0.0 --replset myreplica/localhost:27018,localhost:27017
레플리카 세트 초기화
mongo --port 27017
# admin 데이터베이스 사용
use admin
# 레플리카 세트 구성
var config = {
_id: "myreplica",
members: [
{_id: 0, host: "localhost:27017"},
{_id: 1, host: "localhost:27018"},
{_id: 2, host: "localhost:27019"}
]
}
# 레플리카 세트 초기화
rs.initiate(config)
# 읽기 허용 설정 (읽기 전용 복제본일 경우)
rs.slaveOk()