이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ

게시글

강좌4 - MongoDB - 2년 전 등록 / 7달 전 수정

수정(Update,Upsert 또는 Modify)

조회수:
0
이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ
이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ

안녕하세요. 이번 시간에는 몽고DB CRUD 기능 중 U를 담당하는 Update 메소드들에 대해서 알아보겠습니다.

일단 수정을 하려면 수정할 대상을 선택해야 합니다. 그러고나서 이제 어떻게 수정할 지를 알려줘야겠죠.

Update

가장 유명한 메소드로 update가 있습니다. 슬라임 몬스터를 좀 버프해볼까요? hp가 너무 낮은 거 같아서 올려봅니다.

db.monsters.update({ name: 'Slime' }, { $set: { hp: 30 } }); // WriteResult({ nMatched: 1, nUpserted: 0, nModified: 1 });

수행 결과를 반환하네요. $set을 해야 해당 필드만 바뀝니다. 만약 $set을 넣지 않고 그냥 { hp: 30 } 하면 Slime 다큐먼트가 다 지워지고 { hp: 30 } 이라는 객체로 통째로 바뀌어버립니다. 처음 하는 분들은 이 실수를 정말 많이 합니다.

hp를 너무 많이 올린 것 같아서 다시 원래대로 복구하겠습니다. 그런데 이번에는 좀 다른 방법으로 하겠습니다.

db.monsters.update({ name: 'Slime' }, { $inc: { hp: -5 } }); // WriteResult({ nMatched: 1, nUpserted: 0, nModified: 1 });

$inc를 사용하면 숫자를 올리거나 내릴 수 있습니다. 음수를 넣으면 내리고 양수를 넣으면 올립니다. 위의 코드는 hp를 5만큼 깎은 겁니다.

undefined

첫 번째 인자가 수정할 대상, 두 번째 인자가 수정할 내용입니다. 세 번째 인자로 옵션을 넣을 수 있습니다. 옵션에는 크게 multi와 upsert가 있습니다. multi는 여러 개를 동시에 수정할 때 사용합니다. { multi: true } 하면 됩니다. 기본적으로는 한 다큐먼트만 수정하지만 만약 이름이 Slime인 다큐먼트가 여러 개 있다면 그 다큐먼트들을 모두 수정하는 거죠. upsert는 아래에 따로 설명합니다.

FindAndModify

또한 많이 쓰이는 메소드가 findAndModify입니다. update 메소드와는 달리 upsert과 remove까지 같이 수행할 수 있습니다. 인자가 옵션 객체 하나인데 여러 개의 속성을 넣어줘야 합니다. query가 대상을 찾는 법, update가 대상을 수정할 내용, new가 수정 이전의 다큐먼트를 반환할지, 수정 이후의 다큐먼트를 반환할 지 결정하는 부분입니다. { new: true }를 넣으면 수정 이후의 다큐먼트를 반환합니다. 

데몬 몬스터가 너무 세니 너프해보겠습니다.

db.monsters.findAndModify({ query: { name: 'Demon' }, update: { $set: { att: 150 } }, new: true }); // { 데몬 }

undefined

수정한 후에 수정된 결과를 다시 가져오고 싶다면 update 대신 findAndModify 메소드를 쓰는 게 낫겠죠?

UpdateOne, UpdateMany, ReplaceOne

몽고DB 3.2 버전부터 update를 대체하는 세 메소드가 추가되었습니다. update 메소드와 거의 유사하지만, updateOne은 매칭되는 다큐먼트 중 첫 번째만 수정하고, updateMany는 매칭되는 모든 다큐먼트를 수정합니다. 기존의 multi 옵션이 두 메소드로 나누어졌다고 생각하시면 됩니다.

db.monsters.updateOne({ name: 'Slime' }, { $set: { hp: 25 } });

replaceOne 메소드는 다큐먼트를 통째로 다른 것으로 대체합니다. $set을 안 썼을 때 상황과 유사합니다.

FindOneAndUpdate, FindOneAndReplace

또한 몽고DB 3.2 버전부터 findAndModify 메소드를 대체하는 새로운 두 메소드가 만들어졌습니다. findAndModify는 update, upsert, remove를 모두 담당할 수 있는데요. 이 기능을 쪼개서 하나의 역할만 전담하는 메소드입니다. 역시나 findAndModify 시리즈답게 수정 이전 또는 이후의 다큐먼트를 반환받습니다. 대신 new 옵션이 아니라 returnNewDocument로 이름이 바뀌었습니다.

db.monsters.findOneAndUpdate({ name: 'Demon' }, { $set: { att: 150 } }, { returnNewDocument: true }); // { 데몬 }

Upsert

만약 수정할 대상이 없다면 어떡할까요? 보통의 경우는 아무것도 변하지 않고 종료됩니다. 특정한 옵션을 주어서 수정할 대상이 없는 경우 insert 동작을 수행하도록 할 수 있습니다. 이를 upsert라고 부릅니다. update + insert의 합성어입니다.

Upsert 기능을 하려면 update, updateOne, updateMany, replaceOne 메소드에 옵션으로 { upsert: true } 를 주면 됩니다. 또는 findAndModify, findOneAndUpdate, findOneAndReplace 메소드에 upsert: true를 추가할 수도 있습니다.

Insert 시간에 배웠던 saveinsert 메소드의 차이가 upsert의 개념에 있습니다. save는 upsert 메소드입니다. 만약 해당하는 다큐먼트가 없으면 새로 만듭니다. 하지만 해당하는 다큐먼트가 있으면(_id를 제공해야합니다) 수정합니다.

다음 시간에는 CRUD의 마지막 Delete 관련 메소드에 대해 알아보겠습니다!

투표로 게시글에 관해 피드백을 해주시면 많은 도움이 됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright © 2016- 무단 전재 및 재배포 금지

댓글

2개의 댓글이 있습니다.
한 달 전
findAndModify 실용적이네요 감사합니다.
일 년 전
음 .. 제가 save는 데이터가 없을경우 insert를 실행하게 되고
insert는 데이터가 있든 없든 데이터를 추가한다는 말씀이신거죠??
또 궁금한건 save == upsert인거죠?? ?? upsert를 통해 데이터가 있다면 _id를 제공해야한다는것은 _id가 자동으로 되는게 아니라 직접 추가해주어야 한다는 말씀이신건가요??
일 년 전
save는 upsert랑 비슷합니다. _id를 주지 않으면 insert를 하고, _id를 제공하면 update를 합니다. insert는 데이터가 있든 없든이 아니라 그냥 새로운 하나를 추가하는 겁니다.
일 년 전
아 같은건아니고 비슷한거군요 ㅎㅎ 감사합니다 이해 됬습니다 ㅎㅎ