2011. 9. 15. 17:33

[mongodb] Creating, Updating, and Deleting Documents

* mongodb configure file
; /etc/mongodb.conf

* 클라이언트 실행
; mongo

* document 표현 (JSON-like)
; key/value pair ("key":value)
> node = {"a":1}
> node.a ==> 1 의미
> node_arr = {"arr":["1","2"]}
> node_arr.arr ==> ["1", "2"]
> node_arr.arr[0] = "1"
; null - null 혹은 존재하지 않는 field를 표현 {"x":null}
; object id - 12byte id. document 구분자. {"x": ObjectId()}
; date - {"x":new Date()}. new를 사용해야 함 (JavaScript)
; regular exp. - {"x":/foobar/i}
; code - {"x":function(){...}}
; array - {"x":["a","b","c"]}
; embeded document - {"x" : {"foo":"bar"}}

* show
; show dbs - 현재 db 나열. use로 switch 가능
; show collections - 현재 사용중인 db의 collection 나열. 하나의 db에는 여러개의 collection group 가능

* create
; db.%collection%.insert({"attr":val, "attr2":val, "attr3":val})

* read
; db.%collection%.find({"attr":val, "attr2":val, "attr3":val})
; db.%collection%.findOne({"attr":val, "attr2":val, "attr3":val})

* update
; db.%collection%.update({"attr":val}, {"attr":val,"attr2":val,"attr3":val})
; 동일 attr:val이 많은 경우 처음 한놈만 변경되더라. (자세한건 update multiple documents 참고)

* delete
; db.%collection%.remove({"attr":val})

* document replacement
; schema를 변경하는 일

예) {name=1, a=2, b=3} -> {username=1, val{a=2,b=3}} 형태로 변경
var node = db.%collection%.findOne({"attr":val})
node.val = {"a":node.a, "b":node.b}
node.username = node.name
delete node.name
delete node.a
delete node.b

; 값 변경
node = db.%collection%.findOne({attr:val})
node.val++
db.%collection%.update({attr:val}, node)
==> error (attr.val이 여러개 있는 경우, node에 매치되는 _id가 다름)
db.%collection%.update({"_id":node._id}, node)

* using modifiers
; 특정 영역의 document만 update할 때임 (용어 : partial update, 방법 : update modifiers)

$inc - value 값을 증가 / (-이면 감소)
; db.%collections%.update({"attr":value},{"$inc":{val_attr:inc_val}})
; "attr":value 찾은(처음) document에서 val_attr attribute 값을 inc_val 만큼 증가 시킨다.
; 없는 경우 추가시켜 줌

$set
- value 변경
; db.%collections%.update({"attr":vlaue},{"$set":{setattr:setval}})
; "attr":vlaue 찾은(처음) document에서 setattr:setval 값을 추가(수정)한다. sbling.
; db.%collections%.update({"attr":vlaue},{"$set":{parentattr.childattr:setval}})
; "attr":vlaue 찾은(처음) document에서 childattr:setval 값을 추가(수정)한다. nested child.

$unset
- {"attr",value}를 삭제

$push
- array에 값 추가(수정) (array가 없는 경우 생성)
; db.%collections%.update({"attr":vlaue},{"$push":{"arr":{"arrattr1":val,"arrattr2":val}}})
; "attr":value 찾은(처음) document에서 "arr" id의 array를 추가한다. attrattr1, attrattr2 값으로 구성된 array이다.
; 만일 기존 값이 있었다면, 수정이고, 없었다면 생성이다.
; {"arr":value, "arrattr":[{"arrattr1":val, "attattr2":val}]}로 만든다.

$addToSet
- 값이 없는 경우 추가
; db.a.update({"attr":value},{"$addToSet":{"arrattr":arrval}})
; {"attr":value, "arrattr":[arrval]}로 만든다.
; $push는 동일값이 계속 추가될 수 있음. $addToSet은 없는 경우 추가

$each
- 여러번 실행
; "attr":value에서 value part에서 사용
; db.%collections%.update({"attr":value},{"$addToSet":{"$each":[val1,val2,val3]}}})
--> $addToSet val1, val2, val3을 실행시킨 효과

$pop - array element 삭제
; {"$pop" : {key : 1}} 뒤에서 삭제
; {"$pop" : {key : -1}} 앞에서 삭제

$pull
- array element 삭제 (값)
; {"$pull":{val1,val2}} val1, val2 값 삭제

$
- 배열 수정
; "arr":[{attr.....}, {attr.....}, {attr.....}] 인 경우, arr.0.attr로 index 가능
; db.%collections%.update({"arr.attr":val}, {"$set":{"arr.attr":newval}})
  와 같이 array 값을 찾아 변경 작업을 하면 오류가 발생한다. index가 없기 때문이다.
  db.%collections%.update({"arr.attr":val}, {"$set":{"arr.$,attr":newval}})
  와 같이 $를 넣으면 해결된다.

* upsert (update + insert인 듯함)
; update할 때 값이 없다면 조합에 의해 생성한다(document를). (create by comining)
; 물론 있다면, document를 수정한다. atomic 하다. (해당 명령 수행중에는 다른 명령이 끼어들지 못함)
; db.%collection%.update({"attr":val}, {"attr":val, "attr2":val, "attr3":val}, true)
  와 같이 호출한다. 즉, update 세번째 파라미터에 true를 넘긴다. 즉, 조건이 없다면, 생성시킨다.

* update multiple documents
; update는 default로 first document만 수정한다. update의 네번째 파라미터에 true를 넘기면 된다.
; db.%collections%.update({"a":1}, {$set:{"b":2}}, false, true}
   --> "a":1 이 있는 모든 document에 "b"에 2값을 부여한다.
; 결과 확인은 db.runCommand({getLastError:1})

* findAndModify
; update는 성공여부에 대한 리턴값 없음. getLastError 실행 필요. 그 값은 매우 제한적임.
; 만일, update를 하되 수정된 document를 구하고자 하려면,
result = db.x.find({"attr",old_val})
db.x.update({"_id":result._id}, {"$set":{"attr":new_value}})
db.runCommand({getLastError:1})
do_job(result)
...
와 같이 하게 되는데, 동시에 db.x.find(...)가 여러개 실행되면 꼬일 수 있다. (race condition)
그래서, findAndModify는 다음과 같은 특징이 있다.

; find와 update를 atomic하게 실행. (기타 다른 명령 Option 포함)
; 결과 document를 리턴받음.

result = db.runCommand({"findAndModify":"%collections%",
"query":{"attr":value},
"update":{"$set":{"attr":new_value}})
{
  "ok":1,
  "value": {
   "_id" : ObjectId("..."),
   ...
}
와 같이 리턴값(수정된 document)이 들어온다.

즉, db.runcommand({"findAndModify":...., ..., ....}).value를 하면, 수정된 document 접근이 가능하다.

findAndModify는 여러개의 옵션이 가능한데,
"query", "sort", "update", "remove", "new"가 기본으로 지원된다.

책에서는 findAndModify는 한번에 한개의 document가 update/remove되는 것과, upsert는 지원되지 않는 제약이 있다고 밝히고 있으나, mongodb 1.5.4 이상에서는 upsert가 지원되고 있다.

findAndModify는 좀 느리다. 다시 말해, find, update 그리고 getLastError를 연속으로 실행하는 것 정도로 대략 측정될 것이다.

* safe operation
; mongodb는 속도를 위해 "fire-and-forget" 정책, 즉, 성공/실패 여부를 return하지 않는다. (즉, 기다리지 않는다)
; safe operation은 getLastError를 바로 호출하는 작업을 말한다.
; 되도록 safe operation을 사용하도록 해라.
; 물론, page, user, 광고 통계등 많은 조각 정보가 만들어지는 경우는 fire-and-forget이 좋겠다.

'Research > mongodb' 카테고리의 다른 글

[mongodb] Advanced topics  (0) 2011.09.23
[mongodb] Aggregation (MapReduce)  (0) 2011.09.22
[mongodb] Indexing  (0) 2011.09.22
[mongodb] Querying  (0) 2011.09.19
mongodb, the definitive guide (o'relly, kristina chodorow, michael dirolf)  (0) 2011.09.15