몽고DB 기본 가이드

몽고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()

태그: 몽고DB NoSQL 데이터베이스 집계 인덱스

7월 8일 08:59에 게시됨