본문 바로가기
Database/MongoDB

MongoDB Database 와 Collection 그리고 Document CRUD 하기

by Developer88 2021. 5. 15.
반응형

오늘은 MongoDB에서 가장 기본을 이루는 구조에 대해서 정리해 보려고 합니다.

Database와 Collection 그리고 Document인데요.

이들을 생성해보고 조회해 보는 방법에 대해서 정리해 보도록 하겠습니다.

 

MongoDB의 설치와 실행방법은 아래 글을 참조해 주세요.

>> MongoDB 설치 및 실행 총정리 # MongoDB NodeJS

 

1. MongoDB의 구조

1-1. BSON, Documents, Collection, Database

MongoDB는 documents로 데이터를 저장합니다.

정확히는 BSON이라고 하는 documents인데요.

여기서 BSON은 Binary JSON인데요.

JSON형태의 문서를 바이너리형태로 저장한 것인데, MongoDB는 JSON을 Binary형태로 저장한 document로 저장하는 것 입니다.

 

이런 document들의 묶음이 collections이구요.

하나이상의 Collection의 묶음이 가장 큰 단위인 database입니다.

아래와 같은 계층 구조로 볼 수 있겠지요.

 

BSON(Binary Json)으로 이루어진 Documents > Collection > Database

 

 

2. Database

가장 큰 단위인 Database에 대해서 보도록 하겠습니다.

 

2-1. 사용중인 DB확인

현재 사용중인 데이터베이스를 확인하기 위한 명령어는 다음과 같은데요.

 

db

 

가장 처음, MongoDB를 설치하면 아래와 같이 test라는 database가 선택되어 있다는 것을 알 수 있습니다.

 

 

2-2. DB 리스트

이번에는 모든 데이터베이스 리스트를 보도록 하겠습니다.

 

show dbs

 

그런데 위 명령어를 입력하면 아래와 같은 결과를 보게 됩니다.

이것은 아무 document도 들어있지 않기 때문인데요.

 

 

 

test데이터베이스에 document를 하나 넣어보도록 하겠습니다.

아래와 같이 insertOne()명령어를 이용해 document를 입력해 주면 아래와 같이, test db가 리스팅된 것을 알 수 있습니다.

 

 

2-4. DB생성과 삭제

이번에는 데이터베이스를 생성하거나 삭제해부도록 하겠습니다.

DB를 생성하는 방법은 아래와 같은데요.

 

use <DB이름>

 

use명령어로 "mongo_test"라는 db를 생성하고,

하나의 문서를 insert문으로 생성해 보겠습니다.

생성후에 showdb를 해 보면 문서가 보이는 것을 확인할 수 있습니다.

 

 

바로 생성했던 db를 삭제해보겠습니다.

지우고자 하는 db가 선택되어진 상태에서 아래 명령어를 이용하면 되는데요.

 

db.dropDatabase()

 

 

아래와 같이 잘 삭제된 것을 볼 수 있습니다.

 

 

3. Collection

위에서 insert문으로 document들을 생성해 보았었는데요.

document들로 구성된 것이 바로 Collection입니다.

MySQL같은 관계형DB에서의 Table과 대응되는 개념이겠지요.

 

 

3-1. Collection의 생성

위에서 사용해 본 insert()명령어를 사용할 때,

"db."과 insert() 중간에 적어준 것이 document들의 모음인 Collection의 명칭입니다.

아래에서는 myCollection이 Collection의 명칭이 되겠지요.

 

db.myCollection.insert( { score: 1 } )

 

위에서 했던것과 같이, insert시에 적어주기만 해도 자동으로 생성이 되구요.

 

아래와 같이 "createCollection()" 명령어를 이용해서 생성해 주어도 됩니다.

옵션값은 json형태로 넣을 수 있는데요. 생략 가능합니다.

참고로, autoIndexId는 3.2버전부터는 deprecated되었습니다.

_id에 항상 indexId가 붙는 것이 4.0부터의 디폴트 값이 되었습니다.

 

db.createCollection( <name>,
   {
     capped: <boolean>,
     autoIndexId: <boolean>,
     size: <number>,
     max: <number>,
     storageEngine: <document>,
     validator: <document>,
     validationLevel: <string>,
     validationAction: <string>,
     indexOptionDefaults: <document>,
     viewOn: <string>,              
     pipeline: <pipeline>,          
     collation: <document>,        
     writeConcern: <document>
   }
)

 

 

4. Document의 CRUD

Document는 위에서 언급한 것과 같이, BSON(Binary Json)으로 이루어져 있습니다.

이번에는 Document의 CRUD(Create, Read, Update, Delete)를 해 보도록 하겠습니다.

 

4-1. Document의 생성(Create)

위에서 간단하게 insert()문을 이용해서 document를  생성 해 보았는데요.

BSON이라고 하였지만, Binary형태로 저장하는 것은 MongoDB가 할일로,

DB의 사용자인 저희는 JSON타입으로 저장하고 읽을 수 있습니다.

 

Document는 아래와 같은 구조로 구성되어 있는데요.

 

{
   field1: value1,
   field2: value2,
   field3: value3,
   ...
   fieldN: valueN
}

 

filed에는 다른 document가 들어가도 되구요.

arrays나 document들의 array가 들어갈 수도 있습니다.

아래와 같은 구조도 가능하겠지요.

 

{
   name: { first: "다원", last: "김" },
   contact: { phone: { type: "cell", number: "111-222-3333" } }
}

 

A. 하나의 Document 생성

document하나를 생성할 때는 아래와 같이 insertOne()명령어를 사용할 수 있습니다.

참고로, document의 최대용량은 16메가바이트입니다.

 

db.student.insertOne(
   { name: "하군", score: 100, physical: { height: 185, weight: 90} }
)

 

 

insertOne() 은 자동으로 생성되는 _id 필드를 아래와 같이 return해 줍니다.

 

 

B. 여러개의 Document를 생성

한번에 여러개의 documents를 생성할 수도 있습니다.

 

db.student.insertMany(
   { name: "하군", score: 90, physical: { height: 185, weight: 90} }
   { name: "박군", score: 60, physical: { height: 175, weight: 70} }   
   { name: "김군", score: 86, physical: { height: 165, weight: 60} }
)

 

C. Document 생성과 _id field

각각의 document들은 유니크한 _id 필드를 갖게 되구요.

위에서 생성했던 것 처럼, _id field 를 생략한다면,

Document 생성시에 ObjectId를 자동으로 생성해서 줍니다.

실제 생성된 objectId를 보면 아래와 같은데요.

총12byte의 길이로(24개의 16진수로 구성되어 있습니다.)

 

609e1a0ddb3e17058b9bfe68

 

 

참고로, 총 12byte는 각각 다음과 같은 것들로 구성되어 있습니다.

 

 

4-2. Document의 조회(Read)

이번에는 Document를 Query해서 조회하는 방법을 정리해 보도록 하겠습니다.

test를 위해서 아래와 같이 2개의 document를 insertMany()를 이용해서 생성해 주었습니다.

 

 

A. Select All

먼저 해당 Collection의 모든 Document들을 조회해 보겠습니다.

아래와 같은 명령어로 조회할 수 있습니다.

 

db.Collection명.find( {} )

 

 

아래와 같이, 자동으로 생성된 12byte의 objectId와 함께 두개의 Document가 조회된 것을 볼 수 있었습니다.

 

 

B. 조건에 따른 조회

Json으로 조건을 주어서 조회를 할 수 있는데요.

아래에서는 name이 "김"인 경우를 조회해 보았습니다.

 

 

이하의 값도 구해보겠습니다.

이하의 값을 볼 수 있는 operator는 $lte인데요.

아래와 같이 operator를 쓸 수 있습니다.

 

db.Collection명.find( { field: { $lte: 값 } } )

 

실행해 보면, score가 90점 이하의 값들을 아래와 같이 볼 수 있습니다.

 

 

자주 사용하는 연산자 들로는 다음과 같은 것들이 있습니다.

 

연산자 의미
gte 특정 값보다 이상의 값
lte 특정 값보다 이하의 값
ne
(Not Equal)
값과 같지 않은 값
in array안에 속하는 값
ex> db.mongo_test.find({name: { $in: ["김군", "박군"] }})
or or값
ex> db.mongo_test.find({name: { $or: [{name: "김군"}, {name:"박군"}] }})
and and값
where  

 

 

query Operator를 이용해서, and나 or 혹은 이상이나 이하 값등을 구할 수 있습니다.

아래 링크에서 공식문서의 operator들을 볼 수 있습니다.

>> docs.mongodb.com/manual/reference/operator/query/#std-label-query-selectors

 

 

C. 조회 후의 projection

원하는 field만을 골라서 보는 옵션인데요.

find()의 두번째 인자로 사용해주면 됩니다.

보고자 하는 field를 true로 설정해 주면 됩니다.

예를 들어, 아래는 _id는 보지않고, name 필드만 보고자 할 때 사용할 수 있습니다.

 

db.Collection명.find({}, {“_id”: false, “name”: true} )

 

아래와 같은 결과값을 얻을 수 있습니다.

 

 

4-3. Cursor

위에서 Document를 조회할 때 살펴보았던 find() 메소드는 cursor를 return해 줍니다.

 

A. hasNext()

cursor에는 hasNext()라는 메소드를 이용해 iterate을 할 수도 있구요.

printjson이라는 메소드를 이용할 수도 있습니다.

var myCursor = db.users.find( { type: 2 } );
while (myCursor.hasNext()) {
   printjson(myCursor.next());
}

 

 

위에서 만들어 보았던, mongo_test Collection에 적용해보면 아래와 같이,

모든 값을 볼 수 있게됩니다.

 

 

B. Limit

이름에서 알수 있듯이, 조회갯수에 limit을 거는 것 입니다.

 

db.Collection명.find().limit(최대 data수)

 

 

C. skip

skip()메소드를 이용해서 인자로 넣은 수만큼의 데이터를 생략하고 조회결과값을 받을 수 있습니다.

 

db.Collection명.find().skip(skip하고자 하는 data수)

 

 

4-4. Sort

조회한 데이터를 정렬할 수도 있어야 하는데요.

아래와 같이 find()의 return값인 cursor에 sort()함수를 사용해 주면 됩니다.

오름차순일 경우는 1, 내림차순일 경우는 -1을 인자로 넣어주면 됩니다.

 

db.Collection명.find().sort(<field명>: 오름차순이면 1, 내림차순이면 -1)

 

 

실행해보면, 아래와 같이 오름차순으로 정렬되어 결과값을 받을 수 있습니다.

 

 

4-5. Update

이번에는 Document의 Update에 대해서 알아보도록 하겠습니다.

 

A. updateOne() 과 $set연산자

하나의 document를 업데이트할 때는 updateOne() 메소드를 사용해주면 됩니다.

특정 필드의 값을 변경하고자 할 때는 "$set" 연산자를 사용해 주면 됩니다.

이 set은 만약 업데이트할 값이 필드에 없다면, 새롭게 생성까지 해 줍니다.

 

db.collection명.updateOne(<filter>, <update>, <options>)

 

 

아래는 score를 100으로 update하는 것 입니다.

 

 

 

여기서 filter에 들어가는 값은 조회시 사용하였던 그것과 같구요.

<update>에는 업데이트할 필드와 값을 "$set" 연산자와 함께 사용해주면 됩니다.

마지막 <options>는 여러가지가 있어서 공식문서를 참조하는 것이 좋지만,

upsert 정도는 알고 사용하시면 좋을 것 같습니다.

 

options 의미
upsert boolean 값으로, default는 false로 되어있습니다.
만약 filter에서 조회된 데이터가 없을 경우 새롭게 생성시킨다.

 

 

upsert옵션이 없는 경우, 기존에 없던, "홍"에 대한 update는 아래와 같이 아무변화도 일어나지 않게 되는데요.

 

 

그럼 아래와 같이, filter에서 조회되지 않은 데이터는 새롭게 생성되어 추가된 것을 볼 수 있습니다.

 

 

B. 특정 필드를 제거할 때 $unset

특정필드를 제거하고자 할 때는 $unset 연산자를 다음과 같이 사용해 주면 됩니다.

 

 

 

C. updateMany()

한꺼번에 여러가지 document를 변경하기 위해서는 updateMany()메소드를 이용해 주면 됩니다.

아래와 같이 한번에 여러개를 조회해서 set을 걸수 있습니다.

db.students.updateMany(
   { },
   [
     { $set: { average : { $trunc: [ { $avg: "$tests" }, 0 ] } , lastUpdate: "$$NOW" } },
     { $set: { grade: { $switch: {
                           branches: [
                               { case: { $gte: [ "$average", 90 ] }, then: "A" },
                               { case: { $gte: [ "$average", 80 ] }, then: "B" },
                               { case: { $gte: [ "$average", 70 ] }, then: "C" },
                               { case: { $gte: [ "$average", 60 ] }, then: "D" }
                           ],
                           default: "F"
     } } } }
   ]
)

 

D. save

아래와 같이 업데이트 하는 방법도 있습니다.

 

 

 

4-6. Replace

update와 비슷한 것 같지만 replace라는 개념도 있습니다.

사용방법도 같은데요. _id 필드만 유지되고, 나머지 것은 새롭게 <replace>로 대체됩니다.

 

db.collection명.replaceOne(<filter>, <replace>, <options>)

 

실제로 사용해 보겠습니다.

아래와 같이 3개의 document가 있는 mongo_test Collection이 있는데요.

 

 

 

여기에 아래와 같이 replace를 해주면 아래와 같이 변경되는 것을 볼 수 있습니다.

 

 

4-4. Document의 삭제(Delete)

A. deleteMany

해당 Collection의 모든 document를 삭제하기 위해서는 아래와 같이 명령어를 사용해 주면 됩니다.

 

db.Collection이름.deleteMany({})

 

조건을 주어서 특정 조건에 해당하는 documents들만 삭제할 수도 있습니다.

 

db.Collection이름.deleteMany({name: "박군"})

 

 

B. deleteOne

하나의 document만 삭제할 때는 아래와 같이 해주면 됩니다.

 

db.Collection이름.deleteOne({name: "박군"})

 

5. Tips

5-1. $inc 연산자

필드의 값을 지정된 값만큼 증가시켜주는 연산자 입니다.

굳이 query를 해서 현재값을 알지 않아도 값을 증가시킬 수 있도록 해 줍니다.

아래와 같이, document들이 있다고 가정해 보겠습니다.

 

 

$inc 연산자를 아래와 같이 사용하여, query없이 값을 증가시켰습니다.

(위에서도 보았지만, upsert옵션을 넣어주면, 값이 없을 경우에도 생성해 주게됩니다.)

 

db.mongo_test.update({name:"박"}, {$inc: {score: 10}}, {upsert: true})

 

 

 

5-2. Bulk 연산

MongoDB에는 한번에 여러개의 연산을 모아서 할 수 있는 Bulk연산을 할 수 있습니다.

 

var bulk = db.items.initializeUnorderedBulkOp();
bulk.insert( { item: "abc123", defaultQty: 100, status: "A", points: 100 } );
bulk.insert( { item: "ijk123", defaultQty: 200, status: "A", points: 200 } );
bulk.insert( { item: "mop123", defaultQty: 0, status: "P", points: 0 } );
bulk.execute();

 

mongo_test에 적용해보면, 아래와 같이 사용이 가능합니다.

insert를 여러번 하기보다는 가능하면 bulk를 사용해 주면 효율이 좋습니다.

 

 

 

아래와 같이 정상적으로 들어간 것을 볼 수 있습니다.

 

 

5-3. pretty()

find()의 결과값인 cursor에 pretty()메소드를 사용해주면, 좀 더 보기 쉬운 json형태로 결과를 보여줍니다.

 

6. 정리

이상으로 MongoDB의 Database 와 Collection 그리고 Document에 대해서 정리해 보았구요.

Document를 Crud하는 방법도 정리해 보았습니다.

 

728x90

댓글