2012-04-11 2 views
1

MongoDB에서 일부 개체를 수정하려고 할 때 이상한 동작이 발생합니다. 언어 코드 (lc)를 may에서 msa으로 변경하려고합니다. 텍스트 및 언어 코드에 대한 고유 색인이 있습니다.db.XYZ.update에 의해 중복 키를 업데이트하고 무시하려고하면 실패합니다.

E11000 duplicate key error index: jerome5.Unit.$t_1_lc_1 dup key: { : "laluan", : "msa" } 
: 다음 실패,

db.Unit.find({lc: "may"}, {"t":1}).limit(1000).forEach(function(obj) { 
    try { 
     db.Unit.update({ _id: obj._id }, {$set : { "lc": "msa"}}); 
     print('Changed :' + obj.t + '#' + obj._id); 
    } catch (err) { 
     print(err); 
    } 
}); 

이 개체를 많이 인쇄를 작동하는 것 같다 : I 시도

db.Unit.count({lc: "may"}); 

: {t:1, lc:1}

먼저 나는 카운트를 얻을

이제는 실패가 올바르게 업데이트되기 전에 일치가 예상되지만 카운트를 retur ns는 정확히 같은 숫자입니다.

Javascript로 확실한 것을 놓친 적이 있습니까?

업데이트 : 예외를 발생시키지 않고 인쇄하는 일부 개체는 중복 된 것처럼 보입니다. 오류가 발생하기 전에 약간의 지연이있는 것처럼 보입니다 (저널링이 활성화되어 있습니다). 이것은 정상적인 행동입니까?

답변

6

짧은 대답은 문제가 JS 코드와 관련이 있다는 것입니다.

Mongo의 업데이트는 기본적으로 실행되지 않습니다. 따라서 중복 키로 인해 개별 업데이트가 실패하더라도 "try"문은 계속 성공적으로 완료되고 "catch"섹션의 코드는 실행. forEach 루프가 끝나면 JS 셸은 db.getLastError()를 반환하므로 작업이 성공하면 null을 반환하기 때문에 "catch"코드가 실행되고있는 것처럼 보일 수 있습니다.

간단한 컬렉션을 만들 수 있습니다, 그리고 고유 색인 :

> db.unit.save({_id:0, lc: "may", t:0}) 
> db.unit.ensureIndex({t:1, lc:1}, {unique:true}) 
> for(var i=1; i<10; i++){db.unit.save({_id:i, lc: "may", t:i})} 
> db.unit.find() 
{ "_id" : 0, "lc" : "may", "t" : 0 } 
{ "_id" : 1, "lc" : "may", "t" : 1 } 
{ "_id" : 2, "lc" : "may", "t" : 2 } 
{ "_id" : 3, "lc" : "may", "t" : 3 } 
{ "_id" : 4, "lc" : "may", "t" : 4 } 
{ "_id" : 5, "lc" : "may", "t" : 5 } 
{ "_id" : 6, "lc" : "may", "t" : 6 } 
{ "_id" : 7, "lc" : "may", "t" : 7 } 
{ "_id" : 8, "lc" : "may", "t" : 8 } 
{ "_id" : 9, "lc" : "may", "t" : 9 } 
> 

우리는 실행하려고 http://www.mongodb.org/display/DOCS/getLastError+Command

이 아마도 가장 좋은 예를 통해 설명 : GetLastError 여기 문서에 설명되어 스크립트를 사용하여 모든 "may"값을 "msa"로 변경하십시오. 4 _id : 우리의 스크립트 문서 _id 명중 이제 때

> db.unit.update({_id: 3}, {"lc" : "msa", "t" : 4 }) 
> db.unit.update({_id: 6}, {"lc" : "msa", "t" : 5 }) 
> db.unit.find() 
{ "_id" : 0, "lc" : "may", "t" : 0 } 
{ "_id" : 1, "lc" : "may", "t" : 1 } 
{ "_id" : 2, "lc" : "may", "t" : 2 } 
{ "_id" : 3, "lc" : "msa", "t" : 4 } 
{ "_id" : 4, "lc" : "may", "t" : 4 } 
{ "_id" : 5, "lc" : "may", "t" : 5 } 
{ "_id" : 6, "lc" : "msa", "t" : 5 } 
{ "_id" : 7, "lc" : "may", "t" : 7 } 
{ "_id" : 8, "lc" : "may", "t" : 8 } 
{ "_id" : 9, "lc" : "may", "t" : 9 } 
> 

: 우리가 전에, 그래서 "MSA"인덱스에 중복 값을 만듭니다하는 "수"의 일부 값을 변경, 일부 변경할 수 있습니다 (5), 이렇게하면 "lc"의 값을 "may"로 변경할 수 없으므로 색인에 중복 항목이 작성됩니다.

스크립트 버전을 실행합니다. 당신이 볼 수 있듯이

db.unit.find({lc: "may"}, {"t":1}).limit(1000).forEach(function(obj) { 
    try { 
     print("Found _id: " + obj._id); 
     db.unit.update({ _id: obj._id }, {$set : { "lc": "msa"}}); 
     if(db.getLastError() == null){ 
      print('Changed t :' + obj.t + ' _id : ' + obj._id); 
     } 
     else{ 
      print("Unable to change _id : " + obj.id + " because: " + db.getLastError()) 
     } 
    } catch (err) { 
     print("boo"); 
     print(err); 
    } 
}); 

Found _id: 0 
Changed t :0 _id : 0 
Found _id: 1 
Changed t :1 _id : 1 
Found _id: 2 
Changed t :2 _id : 2 
Found _id: 4 
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1 dup key: { : 4.0, : "msa" } 
Found _id: 5 
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1 dup key: { : 5.0, : "msa" } 
Found _id: 7 
Changed t :7 _id : 7 
Found _id: 8 
Changed t :8 _id : 8 
Found _id: 9 
Changed t :9 _id : 9 
> 

는 "우우"는 인쇄되지 않았다는 "캐치"코드가 실행되지 않았기 때문에, 두 개의 레코드를 업데이트 할 수 없습니다 비록 : 나는 더 상세하게 몇 가지 여분의 라인을 추가했습니다. 기술적으로 update()는 실패하지 않았습니다. 중복 된 인덱스 항목 때문에 문서를 변경할 수 없었고 그 결과에 대한 메시지를 생성했습니다.

변경할 수있는 모든 레코드가 성공적으로 변경되었습니다.스크립트가 다시 실행되면

> db.unit.find() 
{ "_id" : 0, "lc" : "msa", "t" : 0 } 
{ "_id" : 1, "lc" : "msa", "t" : 1 } 
{ "_id" : 2, "lc" : "msa", "t" : 2 } 
{ "_id" : 3, "lc" : "msa", "t" : 4 } 
{ "_id" : 4, "lc" : "may", "t" : 4 } 
{ "_id" : 5, "lc" : "may", "t" : 5 } 
{ "_id" : 6, "lc" : "msa", "t" : 5 } 
{ "_id" : 7, "lc" : "msa", "t" : 7 } 
{ "_id" : 8, "lc" : "msa", "t" : 8 } 
{ "_id" : 9, "lc" : "msa", "t" : 9 } 

은, 다음과 같은 결과가 생성됩니다

Found _id: 4 
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1 dup key: { : 4.0, : "msa" } 
Found _id: 5 
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1 dup key: { : 5.0, : "msa" } 
E11000 duplicate key error index: test.unit.$t_1_lc_1 dup key: { : 5.0, : "msa" } 
> 

당신은 마지막 오류 메시지가 두 번 인쇄 한 볼 수 있듯이 : 우리는 우리의 스크립트에서 인쇄 할 때 한 번, 다시 스크립트가 끝났을 때.

이 응답의 자세한 정보를 용서하십시오. 이것이 JSL 셸에서 getLastError에 대한 이해와 작업이 어떻게 실행되기를 바랍니다.

스크립트는 시도/catch 문없이 재 작성하고 간단하게 업데이트 할 수 없습니다 모든 문서의 _ids 인쇄 할 수 있습니다

db.unit.find({lc: "may"}, {"t":1}).limit(1000).forEach(function(obj) { 
    print("Found _id: " + obj._id); 
    db.unit.update({ _id: obj._id }, {$set : { "lc": "msa"}}); 
    if(db.getLastError() == null){ 
     print('Changed t :' + obj.t + ' _id : ' + obj._id); 
    } 
    else{ 
     print("Unable to change _id : " + obj.id + " because: " + db.getLastError()) 
    } 
}); 
+1

감사합니다 마크 등을 제공하기 위해 시간을내어을 명확한 응답. 'db.getLastError()'의 예제는 내가 필요한 것입니다! –

관련 문제