2014-09-12 3 views
14

실수로 마지막 쿼리에서 일부 문서를 제거했습니다. 마지막 쿼리 문합 컬렉션을 롤백 할 수있는 방법이 있습니까?MongoDB에서 최근에 삭제 된 문서를 복구 할 수있는 방법이 있습니까?

db.datas.remove({ "name" : "some_x_name"}) 

어떤 롤백/취소 옵션이 있습니다 :

은 여기 내 마지막 쿼리입니다? 내 데이터를 다시 가져올 수 있습니까?

+1

중요한 데이터를 작성하는 경우 정기적 인 백업을 수행하는 것이 중요합니다. 이것은 모든 데이터베이스 기술에 적용됩니다. – Sammaye

+1

백업은 항상 좋은 생각이지만 지연과 함께 복제본을 실행하여 최근과 같은 과거의 실수를 수정할 수있는 옵션을 제공합니다. http://docs.mongodb.org/manual/tutorial/configure-a-delayed-replica-set-member/ –

+0

MMS를 사용한 경우 특정 시점 복원을 수행 할 수있었습니다. 롤백 할 다른 방법은 없습니다 !!!! – vmr

답변

17

MongoDB 컨텍스트에서 롤백 옵션 (rollback has a different meaning)이 없으며 엄밀히 말하자면이 문서를 다시 얻을 수있는 지원 방법이 없습니다. 수행 할 수있는 예방 조치는 주석에서 다루고 있습니다. 그렇지만 복제본 집합을 실행하는 경우 단일 노드 복제본 집합이라도 실행하면 oplog이됩니다. 문서를 삽입 할 때 다루는 oplog을 사용하면 문서를 복구 할 수 있습니다.

가장 쉬운 방법은 예제를 사용하는 것입니다. 복원해야하는 100 개의 삭제 된 문서가있는 단순화 된 예제를 사용합니다. 이것 (엄청난 수의 문서 또는 아마도 선택적으로 복원 만하기를 원할 것입니다)을 넘어서려면 커서를 반복하도록 코드를 변경하거나 MongoDB 셸 외부에서 선택한 언어를 사용하여 코드를 작성해야합니다. 기본 논리는 동일하게 유지됩니다.

우선 데이터베이스 dropTest에 예제 콜렉션 foo을 생성 해 보겠습니다.

> db.foo.remove({ "name" : "some_x_name"}) 
WriteResult({ "nRemoved" : 100 }) 
:

use dropTest; 
for(i=0; i < 100; i++){db.foo.insert({_id : i})}; 
for(i=100; i < 200; i++){db.foo.insert({_id : i, name : "some_x_name"})}; 

을 이제 100 개 name 문서의 실수로 제거를 시뮬레이션하자 : 그들은 실수로 나중에 제거 할 수 있도록 우리는 name 필드가없는 (100 개) 문서와 동일한 name 필드 (100 개) 문서를 삽입합니다

우리는 복제 세트에서 실행되기 때문에, 우리는 여전히이 012,350,298,293 (삽입) 및 고맙게도 그 삽입이 없습니다 (아직)를 oplog합니다 (oplog의 마지막을 지나고 떨어진입니다 oplog에서이 문서의 기록을 가지고기억). 우리가 그들을 찾을 수 있는지 보자 :

use local; 
db.oplog.rs.find({op : "i", ns : "dropTest.foo", "o.name" : "some_x_name"}).count(); 
100 

개수가 정확하다고 보이지만 우리는 여전히 문서를 가지고있는 것 같습니다. 나는 우리가 여기에 필요합니다 oplog 항목의 유일한 조각이 o 필드는 것을 경험을 통해 알고, 그래서 그 반환 단지에 돌출부를 추가 할 수 있도록 (간결 냈다 출력을,하지만 당신은 아이디어를 얻을) :

db.oplog.rs.find({op : "i", ns : "dropTest.foo", "o.name" : "some_x_name"}, {"o" : 1}); 
{ "o" : { "_id" : 100, "name" : "some_x_name" } } 
{ "o" : { "_id" : 101, "name" : "some_x_name" } } 
{ "o" : { "_id" : 102, "name" : "some_x_name" } } 
{ "o" : { "_id" : 103, "name" : "some_x_name" } } 
{ "o" : { "_id" : 104, "name" : "some_x_name" } } 

이러한 문서를 다시 삽입하려면 배열에 저장 한 다음 배열을 반복하고 관련 조각을 삽입하면됩니다.

var deletedDocs = db.oplog.rs.find({op : "i", ns : "dropTest.foo", "o.name" : "some_x_name"}, {"o" : 1}).toArray(); 
> deletedDocs.length 
100 

다음으로 우리는 지금 컬렉션의 100 개 삽입을 통해 다음 루프 (100 개) 문서를 가지고 자신을 생각 나게하고, 마지막으로 우리의 카운트 재 검증 : 첫째, 우리의 배열을 만들 수

use dropTest; 
db.foo.count(); 
100 
// simple for loop to re-insert the relevant elements 
for (var i = 0; i < deletedDocs.length; i++) { 
    db.foo.insert({_id : deletedDocs[i].o._id, name : deletedDocs[i].o.name}); 
} 
// check total and name counts again 
db.foo.count(); 
200 
db.foo.count({name : "some_x_name"}) 
100 

을 그리고 거기 당신은 몇 가지주의와, 그것을 가지고 :이 코멘트에서 언급 한 바와 같이, 백업 (MMS, 기타) 그것에 대해, 지연 세컨더리 보면, 진정한 복원하는 전략으로 의미하지 않는다

  • 큰 바쁜 시스템에서 oplog (모든 oplog 쿼리는 테이블 스캔)에서 문서를 쿼리하는 것이 특히 빠릅니다. 언제든지 oplog에서 나이 수
  • 서류는 워크로드에 따라
  • 을 (나중에 사용하기 당신에게 더 많은 시간을 제공하기 위해 당신은 물론, oplog의 복사본을 만들 수 있습니다) 당신은 해제 속는을해야 할 수도 있습니다 이전의 결과는 커서를 반복 할 필요가 있으므로, 입증 된 바와 같이 배열에 대한 너무 큰 것입니다 그들에게 문서의
  • 큰 세트를 다시 삽입하는 대신
  • oplog의 형식은 내부 간주됩니다 및 변경 될 수 있습니다 시간 (예고없이)이므로 사용에 따른 모든 책임은 사용자에게 있습니다.
4

나는 이것이 약간 낡았다는 것을 이해하지만 비슷한 문제를 가진 다른 사람들에게 유용 할 수있는이 분야에서 연구 한 것을 나눠보고 싶었습니다.

MongoDB는 실제로 데이터를 물리적으로 삭제하지 않습니다. 단지 삭제만을 표시합니다. 그러나 이는 버전에 따라 다르며 현재는 설명서 나 표준화가 없으므로 타사 도구 개발자 (또는 절실히 필요로하는 사람)가 도구를 작성하거나 여러 버전에서 작동하는 간단한 스크립트를 안정적으로 작성할 수 있습니다. 이 티켓을 열었습니다 - https://jira.mongodb.org/browse/DOCS-5151.

훨씬 낮은 레벨에있는 하나의 옵션을 탐색하여 사용 된 MongoDB의 버전에 따라 미세 조정이 필요할 수 있습니다. 이해하기 쉽지만 대부분의 사람들이 연결하기에는 너무 낮은 수준이지만 작동하고 다른 모든 것이 실패 할 때 편리 할 수 ​​있습니다.

내 접근 방식은 파일에서 바이너리를 직접 사용하고 파이썬 스크립트 (또는 명령)를 사용하여 삭제 된 데이터를 식별, 읽기 및 압축 해제 (BSON)합니다.

내 접근 방식은 this GitHub 프로젝트에서 영감을 받았습니다 (본인은이 프로젝트의 개발자가 아닙니다). Here on my blog 나는 스크립트를 단순화하고 Raw MongoDB 파일에서 특정 삭제 된 레코드를 추출하려고 시도했다.

현재 레코드 시작 부분에 "\xee"으로 삭제 표시가되어 있습니다. 이

‘\xee\xee\xee\xee\x07_id\x00U\x19\xa6g\x9f\xdf\x19\xc1\xads\xdb\xa8\x02name\x00\x04\x00\x00\x00AAA\x00\x01marks\x00\x00\x00\x00\x00\[email protected]\[email protected]\x00′ 

은 내가 다른 기록에 따라 이전에 확인 된 레코드의 크기로 첫 번째 블록을 교체, 삭제 된 레코드가 원시 DB 파일의 모습입니다.

y=”3\x00\x00\x00″+x[20804:20800+51] 

마지막으로 BSON 패키지 (pymongo와 함께 제공됨)를 사용하여 Readable 객체에 바이너리를 디코딩했습니다.

bson.decode_all(y) 

[{u’_id': ObjectId(‘5519a6679fdf19c1ad73dba8′), u’name': u’AAA’, u’marks': 2000.0}] 

이 BSON은 현재 파이썬 개체이며 복구 컬렉션에 덤프되거나 단순히 어딘지에 기록 될 수 있습니다.

이 복구 기술이나 다른 복구 기술은 데이터베이스 파일의 백업 복사본에있는 준비 영역에서 이상적으로 수행되어야합니다.

+2

답변 해 주셔서 감사합니다! 드문 정보입니다. 정말 도움이 되겠습니까 !! – trex

+0

환영합니다 - 필자는 필자가 작성한 논문의 일부로 Apache Cassandra와 Apache HBase를 사용하여 다양한 수준의 성공을 거두는 방법을 모색했다. –

+2

나는 아주 큰 데이터 덤프를 복구해야하고 위의 링크 주먹은 Mongo 2.4에서 삭제 된 레코드를 올바르게 처리하지 못합니다. @ YazadKhambata가 올바르게 수행했습니다. 그래서 저는 Yazad의 정보를 가지고 요지에서 스크립트를 다시 작성하고 https://gist.github.com/guss77/f8e610cfddbe02c07896을 얻었습니다. 필자는 큰 삭제 된 컬렉션에서 수천 개의 레코드를 복구하는 데이 방법을 사용했습니다. – Guss

관련 문제