MongoDB

2022년 1월 5일 수정

MongoDB 는 이름처럼 Database 시스템이다. 가장 큰 특징은 도큐먼트 기반 데이터베이스, 즉 고정된 스키마가 없는 동적인 데이터를 관리하는 데이터베이스다. 이로 인해 NoSQL DB 의 대명사이기도 하다.

CLI 사용법 메모

연결하기(Connect)

호스트 이름과 포트 번호를 이용해 접속할 때는 아래처럼 사용할 수 있다.

mongo --host foo.bar --port 27017

참고로 27017은 MongoDB 의 기본 포트다. 따라서 이 경우 생략해도 된다.

URI를 이용한 접속도 가능하다.

mongo mongodb://host.foo.bar:27017/dbname

dbname 은 생략할 수 있다.

명령어 노트

데이터베이스 선택(Select Database)

use 명령을 이용해 데이터베이스를 선택할 수 있다.

use dbname

데이터베이스 목록 보기(List Databases)

데이터베이스 이름이 기억나지 않아서 검색해야 될 때는 아래 커맨드를 사용할 수 있다.

db.adminCommand({listDatabases: 1})

왜 이런 중요한 커맨드를 따로 만들어 두지 않았는지 의문이다. 기억 안 나면 어떻게 찾으라는 건지 모르겠다.

컬렉션 조회(List Collections)

컬렉션 조회는 아래처럼 전용 명령어가 있다.

show collections

삽입(Insert)

db.collection.insert({key: value, ...})

데이터베이스에 지정된 도큐먼트를 삽입한다.

조회(Find or Query)

다른 DBMS에서는 쿼리라 부르는 것과 비슷한 검색 혹은 조회하는 기능은 find 명령을 사용한다.

db.colllection.find({key: value, ...})

좀 더 고급 검색 쿼리는 아래에 따로 기록한다.

수정(Update)

특정 도큐먼트의 특정 필드를 업데이트 하는 방법은 아래와 같은 식이다.

db.collection.update({key: value, ...}, {$set: {key: value, ...}})
  • 첫 매개변수는 어떤 도큐먼트인지 검색하기 위한 조건으로 find 에서 쓰는 쿼리와 동일하다.
  • 두 번째 매개변수는 업데이트 하려는 내용을 적는 곳이다.

위 예제는 특정 필드의 값을 업데이트(set) 하려는 경우이고, 도큐먼트를 통째로 갈아 엎으려면 insert 명령과 비슷하게 그냥 두 번째 매개변수에 도큐먼트를 그냥 넣어버리면 된다.

참고로 특정 버전 이후부터 update 명령은 한 개의 도큐먼트만 수정하게 바뀌었다. 모든 도큐먼트 대상으로 업데이트를 하려면 updateMany 명령을 사용하면 된다. 물론 매개변수는 동일하게 사용할 수 있다.

삭제(Delete)

특정 하나의 도큐먼트를 검색해서 삭제하는 방법은 아래와 같다.

db.collection.deleteOne({key: value, ...})

당연히 find 에서 쓰던 쿼리를 그대로 쓸 수 있다.

해당하는 여러 도큐먼트를 한 번에 삭제하고 싶다면 deleteOne 대신 deleteMany 를 사용하자. 사용법은 동일하다.

검색(find) 관련 노트

정렬, 위치, 갯수 제한

db.collection.find({key: value, ...})
             .sort({field: -1})
             .skip(5)
             .limit(10)
sort
위의 경우 field 라는 프로퍼티를 기준으로 내림차순(Descending)으로 정렬된 결과를 얻을 수 있다. 오름차순으로 정렬하려면 -1 대신 1을 넣으면 된다.
skip
검색된 도큐먼트들 중 앞의 몇 개를 생략한다. 위의 경우 첫 5개는 생략한다는 의미다.
limit
검색된 도큐먼트 중 몇 개만 가져온다. 위의 경우 skip 된 이후에 10개의 도큐먼트를 얻어온다는 의미다.

수치 비교

db.collection.find({key: {$gt: 10}})

안타깝게도 일반적으로 쓸 수 있는 수치 비교 연산자인 꺽쇠(>, <)를 쓰지는 못 하고 대신 의미를 가지는 아래 오퍼레이터를 사용할 수 있다.

$gt
왼쪽이 오른쪽보다 큼(Greater Than)
$lt
왼쪽이 오른쪽보다 작음(Less Than)
$gte
왼쪽이 오른쪽 보다 크거나 같음(Greater Than or Equal)
$lte
왼쪽이 오른쪽 보다 작거나 같음 (Less Than or Equal)

특정 필드 표시하지 않기

db.collection.find({key: value, ...},
                   {keyToHide: 0})

find()의 두 번째 필드는 여러 옵션을 줄 수 있는데 이렇게 특정 필드를 결과에서 생략할 수도 있다.

특정 필드가 있는 도큐먼트 검색하기

db.collection.find({key: {$exists: true}})

$exists 를 이용해 특정 필드가 있는 문서 만을 검색할 수 있다. 물론 $exists 의 값을 false 로 해서 특정 필드가 없는 도큐먼트를 조회하는 것도 가능하다.

Not Null

db.collection.find({key: {$ne: null}})

참고로 ne 는 Not Equal 의 약자다.

리스트에 특정 아이템이 있는지 검색하기

db.collection.find({some_list: {$all: ['item1', 'item2', 'item3']}})

위의 커맨드에서 some_list 키는 여러 문자열 데이터를 담고 있는 리스트(list or array)고 여기에 item1, item2, item3이 모두 들어있는 것만 검색이 된다.

여러 후보들 중 일치하는 것 검색하기

db.collection.find({key: {$in: ['item1', 'item2', 'item3']}})

위 명령은 key 필드의 데이터가 item1, item2, 혹은 item3 중 하나일 경우 검색된다.

어그리게이트(Aggregate)

어그리게이트는 도큐먼트를 파이프 라인을 통해 여러 차례에 걸쳐서 처리할 수 있도록 하는 특수한 기능이다. 마치 UNIX 유틸리티를 파이프로 묶어서 결과물을 처리하고 이걸 결과로 넘기는 식이 일렬로 처리되는 것과 비슷하다.

기초

어그리게이트의 기본 문법은 아래와 같다.

db.collection.aggregate([{SYNTAX}, ...])

aggregate 의 매개변수가 리스트라는 점에 주의하자. 리스트 안에 나열되는 식들은 각각 함수나 유틸리티 형태이고, 이 리스트의 순서대로 데이터가 흐르며 처리된다.

예제

db.user.aggregate([
    {$match:
        {created: {$gte: ISODate("2000-01-01T00:00:00")}}
    },
    {$group:
        {_id: '$address',
         count: {$sum: 1}
        },
    },
])

두 개의 기능을 이용한 어그리게이트 예제로, user라는 컬렉션에서 2000년 이후로 가입한 사람들만 간추려서 주소가 같은 사용자의 갯수를 센다고 가정한 예제다.

여기서 제일 처음의 $matchfind 와 비슷하게 컬렉션에서 도큐먼트를 걸러(filter) 내서 다음으로 넘긴다.

그 다음의 $group 은 앞서 필터링 된 도큐먼트를 받아서 address 라는 필터를 기준으로 도큐먼트의 합을 계산한다. $sum 함수는 데이터의 합계를 구하는 함수인데 이 예제에서는 갯수를 세기 위함이므로 1이라는 숫자로 합한다.

몇 가지 유용한 파이프라인 오퍼레이터

$match
필터 혹은 쿼리(find와 비슷)
$group
특정한 필드를 기준으로 모으기(grouping)
$project
도큐먼트의 모양을 바꿈
$lookup
다른 컬렉션의 필드 가져오기(join과 비슷)
$sort
정렬
$limit
갯수 제한
$count
도큐먼트 개수
$unwind
array를 풀어헤치기
$facet
다중 파이프라인 구현

사실상 $match$group 이 가장 많이 쓰이므로 이 둘을 잘 알아두면 유용하게 쓸 수 있다.

더 알고 싶다면 🌏Aggregation Pipeline Stages 문서를 참고해보자.

백업 및 복원(Dump and Restore)

백업(Dump)

아래 예제는 host.foo.bar 라는 DB 서버에서 dbName 이라는 데이터베이스의 collectionName 이라는 컬렉션 중 key의 값이 value인 도큐먼트만 골라서 /foo/bar/dump/directory 라는 디렉터리에 백업하는 명령이다.

mongodump --host host.foo.bar \
          --out /foo/bar/dump/directory \
          --db dbName \
          -c collectionName \
          -q '{key: value}'

그냥 자주 쓸 만한 옵션을 다 붙여서 나열한 것이고 이 중에 필요한 것만 골라서 사용하면 된다. 예를 들어 -q 옵션이 없다면 해당 컬렉션의 모든 도큐먼트를 백업하게 된다.

복원(Restore)

복원할 때는 백업할 때 사용했던 디렉터리를 입력으로 넣어주면 된다.

mongorestore --host host.foo.bar /foo/bar/dump/directory

백업(dump)할 때 데이터베이스 관련 정보도 백업 되므로 복원할 때는 다른 옵션이 필요하지 않다.

기타

컬렉션 몽땅 비우기(지우기)

삭제 커맨드에 별 다른 조건을 주지 않으면 당연히 몽땅 지워져 버린다.

db.collection.remove({})

무서운 커맨드니 조심하자.

최신 버전에서는 remove 대신 deleteMany 커맨드를 써야하는 것 같다. 하나만 삭제하는 커맨드는 deleteOne 이다.

Replica Set 에서 Primary 바꾸기

삽질로 알아낸 정보라 이 방법 외에 다른 방법이 있을 수도 있음을 먼저 알린다.

우선 mongo CLI 도구로 접속해서 설정을 얻어보자.

> cfg = rs.conf()

여기서 members 의 내용에서 ip 주소를 이용해 무엇이 primary인지 파악해보자. 파악이 되면 primary가 아닌 것들의 priority를 낮춰야 한다.

> cfg.members[1].priority = 0.5

1은 그냥 예제일 뿐이고 정확한 인덱스를 입력해야 한다. 0.5라는 수치도 그냥 예제이며 그냥 primary의 priority 보다 작기만 하면 된다.

수치를 다 바꿨으면 설정을 업데이트 해야 한다.

> rs.reconfig(cfg)

이러면 해결이 되면 좋은데 가끔 다시 바뀌는 경우도 있어서 참 곤란한 녀석이다.