모든 MongoDB 도큐먼트는 모든 도큐먼트가 _id 필드를 기본값으로 반드시 가지고 있어야 한다는 공통점이 있습니다.
이 _id 필드의 값은 각 도큐먼트를 구별하는 역할을 합니다.
도큐먼트를 추가할 때 _id 필드와 값을 특정하지 않았다면, 자동적으로 _id 필드가 생성되고 값에 ObjectId 타입이 할당됩니다.
먼저 터미널을 사용해 아틀라스 클러스터에 연결하고, MongoDB에서 제공하는 샘플 데이터를 받아옵니다.
그리고 그 데이터베이스 중 사용하려는 데이터베이스로 이동을 합니다.
화면과 같이 작성된 도큐먼트를 보면, 앞서 설명한 ObjectId 타입(12byte, 24char)의 값이 _id로 작성되어 있는 것을 확인할 수 있습니다.
삽입을 하기 위해서는 insert라는 명령어를 사용하게 됩니다.
insert를 이용하여 도큐먼트를 삽입하기 위해서는 shell에 작성된 것과 같이 insert( )의 괄호 안에 삽입하고자 하는 도큐먼트를 작성합니다.
그리고 이 명령어에 따른 결과물이 하단에 WriteResult로 출력됩니다.
살펴보니 “nInserted”라는 항목이 존재합니다.
이 항목은 삽입된 도큐먼트의 수를 의미합니다.
이 부분이 0인 것으로 보아, 삽입된 도큐먼트가 없다는 뜻이므로 도큐먼트 추가에 실패했다는 것을 알 수 있습니다.
아래 파란색 블록의 부분에서는 _id 값을 삭제한 후 삽입 작업을 실행하였습니다.
그 결과, WriteResult({“nInserted” : 1}) 로 zips 컬렉션에 우리가 작성한 1개의 도큐먼트가 삽입되었다는 것을 알 수 있습니다.
한 번에 다수의 도큐먼트를 삽입하기 위해서는 배열 안에 해당하는 도큐먼트를 담아줘야 합니다.
배열 안 요소인 도큐먼트는 test라는 1개의 필드를 가지고 있고, _id 값은 주어지지 않았습니다.
따라서 inspections 컬렉션 내의 다른 도큐먼트와 구조상으로도, 내용상으로도 중복되지 않은 도큐먼트들입니다.
만약에 중간에 에러가 난다면, 그 뒤부터는 들어가지 않는다.
기본적으로 내장된 순서(주어진 도큐먼트 배열의 인덱스 순서)로 삽입되는 경우, duplicate key 에러가 나오는 순간 작업은 중단됩니다.
나머지 도큐먼트들이 고유한 _id를 가진다고 해도 {"_id" : "3", "test": “3”} 처럼 작업이 진행될 기회가 오지 않습니다.
그러나 삽입하는 작업에 순서가 없다면 고유한 _id를 가지는 모든 도큐먼트는 컬렉션에 추가됩니다.
이를 통해 ordered 옵션을 추가함으로 삽입 순서를 바꿀 수 있다는 것을 알 수 있습니다.
이번에는 존재하지 않는 inspection이라는 컬렉션에 도큐먼트를 삽입해 보았습니다.
그런데 없는 컬렉션에 데이터를 삽입하였음에도 불구하고 아무런 에러가 나지 않았습니다.
MongoDB는 사용자가 쉽게 새로운 컬렉션이나 데이터베이스를 생성하기를 원했습니다.
그래서 만약 사용자가 존재하지 않는 컬렉션에 도큐먼트를 넣는 경우, 그와 동시에 컬렉션이 만들어지게 됩니다.
실제로 컬렉션이 생성되었는지 확인해 보니, 주황색 블록처럼 inspection이 생성된 것을 확인할 수 있습니다.
만약 sample_training 데이터베이스를 사용한다고 하면, use sample_training이라는 명령어를 입력합니다.
이때 sample_training 자리에는 사용하고자 하는 데이터베이스의 이름이 작성되어야 합니다.
데이터베이스가 어떤 컬렉션을 가지고 있는지 보고 싶다면 앞서 데이터베이스 리스트를 확인하기 위해서 사용했던 show라는 명령어를 다시 사용합니다.
show collections라는 명령어를 입력하면, sample_training 데이터베이스 안의 컬렉션 리스트가 나타나는 것을 확인할 수 있습니다.
zips라는 컬렉션에는 미국의 우편번호 관련 데이터가 저장되어 있습니다.
뉴욕 주의 우편번호 관련 데이터를 조회하려고 합니다.
이때 드디어 find라는 명령어를 사용합니다.
명령어에서 db는 sample_training 데이터베이스를 가리킵니다.
db.zips.find({“state” : “NY”})의 결과물이 다음과 같이 JSON 형식으로 화면에 출력되는 것을 볼 수 있습니다.
이때 find 명령어에 따른 실제 결과물은 화면에 출력된 것보다 훨씬 많지만 화면에는 랜덤하게 선택된 20개 결과물만 출력됩니다.
해당 조건에 맞는 다음 20개의 도큐먼트를 조회하기 위해서는, 화면의 주황색 블록과 같이 iterate의 줄임말인 it 명령어를 사용해야 합니다.
만약 zips 컬렉션의 데이터 중 뉴욕 주에 위치한 ALBANY시의 우편번호만 보고 싶다고 하면 그 조건을 find(<쿼리문1, 쿼리문2>)의 형태로 적어주면 됩니다.
따라서 터미널의 실행 예시인 db.zips.find({“state” : “NY”, “city” : “ALBANY”})와 같이 작성합니다.
만약 zips 컬렉션의 데이터 전체를 보고 싶다고 하면
터미널에 작성된 코드와 같이 find 명령어를 조건 쿼리문 없이 사용하면 됩니다.
만약 보기가 불편해서 pretty()라는 명령어를 덧붙인다면 이런 식으로 나온다.
하지만 지금까지 했던 것들은 20개씩 뜨기 때문에 전체 데이터의 수를 조회할 수가 없다.
그렇게 하기 위해서는 count()라는 명령어를 사용한다.
그렇게 하면 연두색 블록과 같이, zips 컬렉션 안 모든 데이터의 수가 출력이 됩니다.
특정한 1개의 데이터만을 조회하려고 한다면 findOne이라는 명령어를 사용하면 된다.
findOne()은 무작위로 1개의 데이터만 가지고 오고 MongoDB의 도큐먼트를 구별하는 고유한 값인 _id를 조건으로 주어 데이터를 특정하면 그 결과로 주황색 블록과 같이 데이터 1개가 출력되는 것을 볼 수 있습니다.
mongo shell에서 도큐먼트를 업데이트하기 위한 방법에는 updateOne, updateMany 2가지가 있습니다.
updateOne은 findOne과 같이 주어진 기준에 맞는 다수의 도큐먼트가 있다면, 그중 기준에 맞는 첫 번째 도큐먼트 하나만 업데이트가 됩니다.
반면에 updateMany를 사용하면 명령어 자체에서도 알 수 있듯, 쿼리문과 일치하는 모든 도큐먼트를 업데이트하게 됩니다.
다음 아래 사진에 있는 pop 필드인 인구수를 10명씩 updataMany를 활용해 늘려보겠다.
우선 updateMany 명령어를 사용합니다.
명령어의 첫 번째 인자에는 어떤 도큐먼트를 업데이트할지 결정하는 조건이 들어갑니다.
우리는 {“city”: “ALPINE”} 이라는 조건의 지역 인구수 데이터를 업데이트할 것이기 때문에, 첫 번째 인자에 {“city”: “ALPINE”} 쿼리문을 작성했습니다.
두 번째 인자는 발생할 업데이트 내용을 특정합니다.
MQL(MongoDB Query Language) 업데이트 연산자인 $inc를 슬라이드에 표현된 형태처럼 작성하면, 특정 필드의 값을 원하는 만큼 증가시킬 수 있습니다.
우리는 ALPINE이라는 값을 가진 모든 도큐먼트의 pop 필드를 10만큼씩 증가시킬 것이기 때문에, {"$inc" : {"pop" :10}} 와 같은 쿼리문을 작성했습니다.
작업에 대한 응답을 살펴보면, matchedCount와 modifiedCount로 나뉩니다.
해당 부분은 명령어에 들어가는 쿼리문 2개에 대한 응답입니다.
matchedCount는 첫 번째 인자로 들어간 조건을 충족하는 도큐먼트의 수를 의미합니다.
여기서는 우리가 앞서 찾았던 도큐먼트의 수인 9가 출력되었습니다.
modifiedCount는 두 번째 인자로 들어간 업데이트 연산자 $inc로 인해 수정된 도큐먼트의 수를 의미합니다.
matchedCount와 modifiedCount가 동일한 값으로 출력되었습니다.
이를 통해 실제로 도큐먼트의 pop 필드가 성공적으로 업데이트된 것을 확인할 수 있었습니다.
updateOne도 updateMany와 사용법은 같습니다. 유일한 차이점은 업데이트하는 데이터의 수입니다.
$set 연산자를 사용하면 주어진 필드에 지정된 값을 업데이트합니다.
슬라이드 화면과 같이 기존의 pop 필드는 21205 값을 가지고 있었습니다.
$set 연산자를 사용하여 바꾸고 싶은 값을 pop 필드에 작성했습니다.
그러자 첫 번째 인자인 {“zips”: “12534”}에 해당하는 도큐먼트의 pop 필드가 $set 연산자를 사용해 지정한 값인 6235로 변경된 것을 확인할 수 있습니다.
zips 컬렉션에 인구수를 의미하는 필드는 pop이라고 작성되어 있습니다.
이 부분을 population이라고 잘못 작성했다고 가정해 보겠습니다.
에러가 발생할 것이라고 예상할 수도 있지만, 슬라이드와 같이 해당 도큐먼트 안에 잘못 작성된 필드가 그대로 추가되는 것을 볼 수 있습니다.
MongoDB 는 주어진 필드 이름이 기존에 없는 이름인 경우, 해당 필드를 추가합니다.
따라서 현재 이 도큐먼트 안에는 같은 값을 가지는 pop과 population 두 개의 필드가 존재합니다.
$set 연산자는 $inc 연산자와 같이 다양한 필드에 값을 지정하기 위해서도 사용 가능합니다.
$push 연산자는 간단하게 말하자면, 배열로 이루어진 필드의 값에 요소를 추가하기 위한 연산자입니다.
extra credit은 class_id가 339이고, student_id가 250인 학생에게 준다고 가정하겠습니다.
업데이트할 도큐먼트를 {“student_id” : 250, “class_id” : 339} 조건으로 지정합니다.
{“type” : “extra credit”, “score” : 100} 형태의 서브 도큐먼트를 scores 필드의 값인 배열에 추가해야 하기 때문에,
배열로 이루어진 필드의 값에 해당 서브 도큐먼트를 추가하기 위한 연산자인 $push를 써서 작성합니다.
슬라이드 상단의 응답 메시지와 같이 첫 번째 인자에 해당되는 도큐먼트가 1개 존재하고, 두 번째 인자에 해당되는 형태로 업데이트된 도큐먼트가 1개 존재합니다.
확인해 보기 위해서 다시 해당 도큐먼트를 find 명령어로 찾아보니, scores 필드의 값인 배열 안에 서브 도큐먼트가 삽입된 것을 알 수 있었습니다.
deleteOne( )은 주어진 기준에 맞는 다수의 도큐먼트 중 첫 번째 도큐먼트 하나를 삭제합니다.
검색 쿼리문의 조건에 맞는 다수의 도큐먼트가 있다면, 의도하지 않은 도큐먼트가 삭제될 수 있습니다.
그렇기 때문에 deleteOne( )을 사용하는 경우 _id 값으로 쿼리해 온 도큐먼트를 삭제하는 것이 좋은 접근법입니다.
기준을 충족하는 도큐먼트가 많을 경우에는 deleteMany를 사용하여 다수의 도큐먼트를 삭제할 수도 있습니다.
컬렉션을 삭제하기 위해서는 drop이라는 명령어를 사용해야 합니다.
drop 명령어를 작성하는 방법은 슬라이드 화면과 같습니다.
이때 collection_name에는 삭제하고자 하는 컬렉션의 이름을 적어주면 됩니다.