MongoDB
→ DB 접속방법과 Collection 삭제 및 수정, Document 생성 및 조회에 대하여


터미널에서 mongosh 접속한 상태에서 사용할 수 있는 명령 (나의 경우 mongosh --port 27018 를 통해 mongo shell 사용했으며, NOSQLBooster 툴 내 쿼리 편집기에서 사용 가능)

# DB 사용
use testDB # testDB라는 데이터베이스가 있으면 접속, 없으면 생성해서 접속

# 컬렉션에 데이터 insert
# 마찬가지로 "myCollection" 이라는 이름의 컬렉션이 없으면 생성해서 Data isnert
db.myCollection.insertOne({x:1}) 

# 현재 세팅(접속)된 데이터베이스 확인
db

# 데이터베이스 목록 확인
show dbs

# 세팅된 데이터베이스 안에 있는 컬렉션 목록
show collections


데이터베이스와 컬렉션의 삭제와 수정

# db삭제
db.dropDatabase()

# 컬렉션삭제
db.삭제할컬렉션명.drop()

# 컬렉션명 변경
db.변경대상컬렉션명.renameCollection(이름);

MongoDB에서는 데이터베이스 이름을 변경할 수 없다. 스토리지 엔진의 구조적인 문제로 저장된 전체적인 내용이 바뀌어야 하는데, 복제와 샤딩까지 된 상태에서 이것을 실시간으로 바꾸는 것은 불가능하기 때문이라고 한다. (이렇듯 MongoDB 개발팀에서는 불확실한 기능을 제공하기보다는 해당 기능을 마련하지 않는 것으로 결정했고, ‘비공식’적으로 새로운 데이터베이스로 복사, 클론하는 방법이 존재)


Capped Collection

일반적인 컬렉션과 다르게 정해진 크기를 초과하게 되면, 자동으로 가장 오래된 데이터를 삭제하는 기능을 가지는 컬렉션.

컬렉션 생성시 추가적인 옵션을 통해 생성 가능

db.createCollection(<컬렉션 이름>, {capped: true, size:<제한할 크기>})

※ 제한 크기가 4096보다 작으면 4096으로 고정. 기본적으로 차지하는 크기가 있기 때문.

로그 데이터나, 일정시간 동안만 보관하는 통계 데이터를 보관하고 싶을 때 유용

실습

db.createCollection("cappedCollection", {capped: true, size: 10000});

db.cappedCollection.insertOne({x:1});

db.cappedCollection.find();

db.cappedCollection.stats();

for( i=0 ; i < 1000 ; i++){
    db.cappedCollection.insertOne({x:i})
}

db.cappedCollection.find();

※ insertOne을 통해 컬렉션에 도큐먼트를 넣을 때 ‘_id’ 키에 값을 직접 지정하면 자동으로 랜덤하게 들어갔던 _id의 value를 사용자 임의의 값으로 넣을 수 있다.


db.enableFreeMonitoring() 무료 클라우드 모니터링 기능 활성화 명령어 반환되는 url을 통해 해당 데이터베이스의 상태 확인 가능


writenConcern : 데이터 손실이 일어나는 최악이 상황을 어느 정도 수준으로 막을지 결정하게 돕는 옵션. 보수적으로 설정할 수록 안정적이지만 성능이 떨어지는 문제.


다수 도큐먼트 생성

db.collection.insertMany(
	[<document1>, <document2>, ...]
)

이러한 insertMany를 통해 값을 insert하는 경우 원자성을 갖지 못한다.

*원자성 : 완전히 성공이거나 완전히 실패만 가질 수 있는 성질. 즉 일부만 성공, 일부만 실패가 될 수 없는 성질

원자성이 없는 insertMany는 1만원 입금 후, 2만원을 입금하듯 별개의 행위로 취급된다. 하지만 MongoDB 4.0 버전 이상부터는 ‘트랜잭션’이라는 기능이 생겨서 원자성을 성립시킬 수 있다.


도큐먼트 필터링 조회

# 조건 한개
db.컬렉션명.find({name:'가위'})

# 조건 한개 이상
db.컬렉션명.find({name:'가위', category:'animal'})
#  명시한 조건(필드) 순서가 달라져도 검색결과는 달라지지 않는다.

점 연산자

var a = {name: {firstName:"Karoid", lastName:"Jeong"}}
a.name.firstName

# 결과 : Karoid

# 이것을 응용하여 필터링
db.A.find({"name.firstName":"Karoid"})
B컬렉션 안에 numbers 필드에 다음과 같은 도큐먼트가 있다고 할때
{numbers : [ 101, 32, 21, 11 ]}
{numbers : [ 64, 94, 15 ]}
{numbers : [ 52, 68, 75 ]}

배열의 첫번째가 52 값을 찾는 방법
db.B.find( {"numbers.0" : 52} )

이렇듯, 파라미터를 통해 어떤 도큐먼트를 불러올지 정하는 것을 쿼리(Query)

반면, 어떤 도큐먼트의 어떤 필드값을 노출할지 결정해주는 파라미터를 프로젝션(Projection)

find 함수의 첫번째 인자값이 쿼리. 두번째 인자값이 프로젝션

true, false 혹은 1, 0으로 출력 여부 표시

참고로, _id 필드는 프로젝션 파라미터로 false를 지정하지 않으면 항상 표시되도록 되어있다.

> db.컬렉션명.find(null, {name:false})
# 결과
{"_id":ObjectId("5c6cd41ab6be2d966aaa5e2a"), "weight":60, "category":"animal"}

########################################################################

> db.컬렉션명.find(null, {_id:false, name:false})
# 결과
{"weight":60, "category":"animal"}

필드를 잘못 설정한 예

> db.컬렉션명.find(null, {_id:false, name:true, weight:false})

결과 : 에러 발생
name 필드만 표시하고 싶다면 그냥 _id:false, name:true 까지만 입력하면 된다.

정리하자면 프로젝션을 설정할 때 _id필드를 제외한 필드들을 설정할 때 참, 거짓 이 두 값 중 하나만 존재하도록 설정해야한다.

{name : 1} // O
{name : 1, category : 1} // O
{_id : 0, name : 1, category : 1} // O
{name : 0, category : 1} // X
{name : 1, category : 0} // X


Cursor

find의 결과값이 크고 샤딩이 되어있다면 모든 샤드에서 도큐먼트를 불러들이기 때문에 시간은 훨씬 더 많이 필요할텐데, 이를 효율적으로 처리하기 위해서 포인터를 이용하여 도큐먼트의 위치정보만을 반환, 검색결과를 batch라는 곳에 모아 놓고 부분부분 커서로 가리키며 호출하는 방식

var cursor = db.cappedCollection.find()

db.cappedCollection.find()
// 결과값 : {"_id" : Objection(~), "x" : 690}

cursor.next()
// 결과값 : {"_id" : Objection(~), "x" : 709}

cursor.hasNext()
// 결과값 : true

/* 모든 도큐먼트 반환 */
db.cappedCollection.find().toArray()

모든 도큐먼트 반환

db.cappedCollection.find().toArray()

이는 메모리 용량을 초과하는 문제가 발생할 수 있다. 이러한 상황을 방지하기 위해 forEach를 사용할 수 있다.

db.cappedCollection.find().forEeach(function(){
 <어떤작업> 
})

Leave a comment