2019. 9. 16. 21:16ㆍDatabase/MongoDB
이번 포스팅은 몽고디비 CRUD 3번째 글입니다. 이번 내용은 문서 update부터 다루어볼 예정입니다. 혹시나 이전 포스팅을 못 보신분들은 간단히 아래 링크에서 참고 부탁드립니다.
Update Documents
예제에 앞서 아래 문서들을 삽입해줍니다. 아래 문서들을 이용해서 예제를 진행할 것입니다.
1
2
3
4
5
6
7
8
9
10
11
12
|
db.inventory.insertMany( [
{ item: "canvas", qty: 100, size: { h: 28, w: 35.5, uom: "cm" }, status: "A" },
{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "mat", qty: 85, size: { h: 27.9, w: 35.5, uom: "cm" }, status: "A" },
{ item: "mousepad", qty: 25, size: { h: 19, w: 22.85, uom: "cm" }, status: "P" },
{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "P" },
{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
{ item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" },
{ item: "sketchbook", qty: 80, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "sketch pad", qty: 95, size: { h: 22.85, w: 30.5, uom: "cm" }, status: "A" }
] );
|
cs |
-Update Documents in a Collection
몽고디비에선 문서 업데이트를 위해 $set와 같은 업데이트 연산자를 제공하여 필드값을 수정한다. $set과 같은 몇몇 수정 연산자는 필드가 존재하지 않을 경우 필드를 생성해준다.
-Update a Single Document
db.collection.updateOne() 명령어를 이용해서 단일 문서 수정을 수행한다.
> db.inventory.updateOne({item:"paper"},{$set:{"size.uom":"cm",status:"P"},$currentDate:{lastModified:true}})
위 쿼리는 item이 paper인 첫번째 문서의 임베디드 문서 필드인 size 필드의 uom값을 cm으로 status필드의 값을 P로 바꾸어준다. 그리고 $currentDate 연산자를 사용하여 lastModified 필드의 값을 현재 날짜로 업데이트한다. 만약 lastModified 필드가 없으면 $currentDate가 필드를 만들어 값을 넣어준다.
-Update Multiple Documents
db.collection.updateMany() 명령어를 이용해서 다수의 문서를 한번에 수정한다.
> db.inventory.updateMany({qty:{$lt:50}},{$set:{"size.uom":"in",status:"P"},$currentDate:{lastModified:true}})
위 쿼리는 qty 필드의 값이 50보다 작은 모든 문서에 대해 $set 연산자에 대한 필드를 수정하고, lastModified 필드에 변경 날짜와 시간을 넣어준다.
-Replace a Document
_id 필드를 제외한 문서의 전체 내용을 바꾸려면 완전히 새로운 문서를 두 번째 인수로 db.collection.replaceOne()에 전달한다.
문서를 교체 할 때 교체 문서는 필드 / 값 쌍으로 만 구성되어야한다. 즉, 업데이트 연산자 표현식을 포함하면 안된다.
대체 문서는 원본 문서와 다른 필드를 가질 수 있다. 대체 문서에서 _id 필드는 변경할 수 없으므로 _id 필드를 생략 할 수 있다. 그러나 _id 필드를 포함 시키면 현재 값과 동일한 값을 가져야한다.
> db.inventory.replaceOne({item:"paper"},{ item:"paper", instock:[{warehouse:"A",qty:60},{warehouse: "B", qty: 40}]})
위 쿼리는 item이 paper인 첫번째 문서를 두번째 인자인 문서로 교체해준다. _id 필드를 생략하였으므로 기존과 동일한 _id필드를 가지며, 혹시나 _id 필드를 넣더라도 대체하길 원하는 문서의 _id값과 동일하게 넣어줘야한다.
여기까지 간단히 수정 쿼리을 다루어봤는데, 조금더 자세히 수정쿼리에 대해 다루어보자.
Method | 설명 |
db.collection.updateOne() |
여러 문서가 지정된 필터와 일치하더라도 지정된 필터와 일치하는 최대 하나의 문서를 업데이트한다. 버전 3.2의 새로운 기능. |
db.collection.updateMany() | 지정된 필터와 일치하는 모든 문서를 업데이트한다. |
db.collection.replaceOne() |
여러 문서가 지정된 필터와 일치하더라도 지정된 필터와 일치하는 최대 하나의 문서를 대체한다.
버전 3.2의 새로운 기능 |
db.collection.update() |
지정된 필터와 일치하는 단일 문서를 업데이트하거나 지정된 필터와 일치하는 모든 문서를 업데이트한다. 기본적으로 해당 Method는 단일 문서를 업데이트한다. 여러 문서를 업데이트하려면 multi 옵션을 사용한다. |
-추가적인 업데이트 Method
Method |
db.collection.findOneAndReplace() |
db.collection.findOneAndUpdate() |
db.collection.findAndModify() |
db.collection.save() |
db.collection.bulkWrite() |
Delete Documents
문서 삭제에 대한 예제를 다루어봅니다.
-Delete All Documents
특정 컬렉션의 모든 문서를 삭제하기 위해서는 필터 값에 아무런 값을 넣지 않고 db.collection.deleteMany() 메서드를 작성하면 된다.
> db.inventory.deleteMany({})
해당 컬렉션에 모든 문서를 삭제하고 삭제대상이 된 문서의 갯수를 결과로 반환한다.
-Delete All Documents that Match a Condition
삭제할 문서를 식별하는 기준 또는 필터를 지정할 수 있다. 필터는 조회 쿼리와 동일한 구문을 사용한다.
> db.inventory.deleteMany({status:"A"})
위 쿼리는 status 값이 A인 모든 문서를 삭제한다.
-Delete Only One Document that Matches a Condition
지정된 필터와 일치하는 문서를 하나만 삭제할때 db.collection.deleteOne()을 사용한다.
> db.inventory.deleteOne({status:"D"})
Delete Behavior
-Indexes
컬렉션에서 모든 문서를 삭제하더라도 인덱스는 삭제하지 않는다. (이것은 인덱스의 내부 구조에 대한 내용까지 들어갈 듯한데, 보통 B+Tree에서 인덱스 삭제 연산이 있더라도 삭제 플래그값만 남기고 값은 바로 삭제하지 않았던 걸로 기억. 정확히 아시는 분은 댓글로 좀 부탁드립니다...)
삭제 연산에 사용되는 Method들은 아래와 같다.
Method | 설명 |
db.collection.deleteOne() |
여러 문서가 지정된 필터와 일치하더라도 지정된 필터와 일치하는 문서를 하나만 삭제한다. 버전 3.2의 새로운 기능. |
db.collection.deleteMany() |
지정된 필터와 일치하는 모든 문서를 삭제한다. 버전 3.2의 새로운 기능. |
db.collection.remove() | 지정된 필터와 일치하는 단일 문서 또는 모든 문서를 삭제한다. |
-추가적인 문서삭제 Method
Method | 설명 |
db.collection.findOneAndDelete() | 해당 메서드는 정렬 옵션을 제공한다. 이 옵션을 사용하면 지정된 순서대로 정렬된 첫번째 문서를 삭제한다. |
db.collection.findAndModify() | 해당 메서드는 정렬 옵션을 제공한다. 이 옵션을 사용하면 지정된 순서대로 정렬된 첫번째 문서를 삭제할 수 있다. |
db.collection.bulkWrite() |
Bulk Write Operations
몽고디비는 클라이언트에게 벌크작업을 수행할 수 있는 기능을 제공한다. 벌크작업은 단일 컬렉션에 대해서만 수행가능하다. 몽고디비는 애플리케이션이 벌크작업에 필요한 수용 가능한 Acknowledgement 수준을 결정할 수 있도록한다.
db.collection.bulkWrite() 메소드는 대량 삽입, 업데이트 및 제거 작업을 수행하는 기능을 제공한다. MongoDB는 db.collection.insertMany()를 통한 대량 삽입도 지원한다.
-Ordered vs Unordered Operations
벌크작업은 작업에 순서가 있거나 순서가 맞지 않을 수 있다.
순서가 지정된 작업 목록을 사용하여 MongoDB는 작업을 순차적으로 실행한다. 쓰기 작업 중 하나를 처리하는 동안 오류가 발생하면 MongoDB는 목록에 남아있는 쓰기 작업을 처리하지 않고 반환한다.
정렬되지 않은 작업 목록을 사용하면 MongoDB가 작업을 병렬로 실행할 수 있지만이 동작은 보장되지 않는다. 쓰기 작업 중 하나를 처리하는 동안 오류가 발생하면 MongoDB는 목록에 남아있는 쓰기 작업을 계속 처리한다.
분할 된 컬렉션에서 정렬 된 작업 목록을 실행하면 정렬 된 목록을 사용하여 정렬되지 않은 목록을 실행하는 것보다 일반적으로 속도가 느려진다. 각 작업은 이전 작업이 완료 될 때까지 기다려야한다.
기본적으로 bulkWrite ()는 순서가 지정된 작업을 수행한다. 순서가없는 쓰기 작업을 지정하려면 옵션 문서에서 ordered : false를 설정하면 된다.
즉, 벌크 연산은 아래와 같은 오퍼레이션과 동일한 역할을 수행할 수 있다.
insertOne |
insertMany |
updateOne |
updateMany |
replaceOne |
deleteOne |
deleteMany |
1
2
3
|
{ "_id" : 1, "char" : "Brisbane", "class" : "monk", "lvl" : 4 },
{ "_id" : 2, "char" : "Eldon", "class" : "alchemist", "lvl" : 3 },
{ "_id" : 3, "char" : "Meldane", "class" : "ranger", "lvl" : 3 }
|
cs |
characters 컬렉션에는 위와 같은 문서가 있다고 가정한다. 이 컬렉션에 아래와 같이 벌크 연산을 수행할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
try {
db.characters.bulkWrite(
[
{ insertOne :
{
"document" :
{
"_id" : 4, "char" : "Dithras", "class" : "barbarian", "lvl" : 4
}
}
},
{ insertOne :
{
"document" :
{
"_id" : 5, "char" : "Taeln", "class" : "fighter", "lvl" : 3
}
}
},
{ updateOne :
{
"filter" : { "char" : "Eldon" },
"update" : { $set : { "status" : "Critical Injury" } }
}
},
{ deleteOne :
{ "filter" : { "char" : "Brisbane"} }
},
{ replaceOne :
{
"filter" : { "char" : "Meldane" },
"replacement" : { "char" : "Tanys", "class" : "oracle", "lvl" : 4 }
}
}
]
);
}
catch (e) {
print(e);
}
|
cs |
벌크 연산의 결과는 아래와 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"acknowledged" : true,
"deletedCount" : 1,
"insertedCount" : 2,
"matchedCount" : 2,
"upsertedCount" : 0,
"insertedIds" : {
"0" : 4,
"1" : 5
},
"upsertedIds" : {
}
}
|
cs |
샤드 컬렉션에 벌크 연산 전략
초기 데이터 삽입 또는 일상적인 데이터 가져오기를 포함한 벌크삽입 연산 작업은 샤드 클러스터 성능에 영향을 줄 수 있다. 벌크삽입의 경우 다음 전략들을 고려할 수 있다.
-컬렉션 사전 분할
샤딩된 컬렉션이 비어 있다면, 컬렉션은 하나의 초기화된 청크만 갖고 있는다. 그런 다음 몽고디비는 데이터를 수신한 이후에 분할을 생성하고 분할 청크를 사용 가능한 샤드에 분배한다. 즉, 리소스가 어느정도 큰 작업이 될것이다. 이 성능 비용을 줄이기위해 벌크작업 이전에 컬렉션을 사전 분할 할 수 있다.
-순서없는 벌크 연산
샤드 클러스터에 대한 쓰기 성능을 향상시키려면 벌크연산의 선택적인 매개변수인 orderded를 false로 설정하면 된다. 이 설정은 순서없이 작업을 수행하는데, 병렬로 수행하기 때문에 여러 샤드에 동시에 작업수행이 가능하다. 하지만 이 작업을 하기 전에는 컬렉션이 미리 분할되어 있어야한다.
여기까지 수정,삭제,벌크 연산에 대해 다루어봤습니다. 이후 포스팅에서 더 다양한 연산들을 다루어보겠습니다.
'Database > MongoDB' 카테고리의 다른 글
DB - MongoDB Text Search(본문 검색) (0) | 2019.09.16 |
---|---|
DB - MongoDB와 자주 사용되는 SQL 비교 (0) | 2019.09.16 |
DB - MongoDB CRUD 사용방법 및 기타 사용방법 - 2 (0) | 2019.09.16 |
DB - MongoDB CRUD 사용방법 및 기타 사용방법 - 1 (0) | 2019.09.13 |
DB - MongoDB 조건으로 일부 문자열만 사용하여 인덱스이용하기 (0) | 2019.09.13 |