2014-09-12 40 views
14

Tôi đã xóa một số tài liệu trong truy vấn cuối cùng của mình do nhầm lẫn, Có cách nào để khôi phục bộ sưu tập mongo truy vấn cuối cùng của tôi không.Có cách nào để khôi phục các tài liệu đã xóa gần đây trong MongoDB không?

Dưới đây là câu hỏi cuối cùng của tôi:

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

Có rollback tùy chọn/undo? Tôi có thể lấy lại dữ liệu của mình không?

+1

Không phải trong trường hợp này, điều quan trọng là luôn luôn thực hiện sao lưu thường xuyên nếu bạn đang thực hiện dữ liệu có giá trị; Điều này đi cho bất kỳ cơ sở dữ liệu công nghệ – Sammaye

+1

Sao lưu luôn luôn là một ý tưởng tốt, nhưng bạn cũng có thể chạy một bản sao với một sự chậm trễ để cung cấp cho bạn một tùy chọn để sửa lỗi trong quá khứ gần đây như thế này: http://docs.mongodb.org/manual/tutorial/configure-a-delay-replica-set-member/ –

+0

Bạn có thể đã khôi phục lại thời gian nếu bạn sử dụng MMS. Không có cách nào khác để rollback !!!! – vmr

Trả lời

17

Không có tùy chọn cuộn ngược (rollback has a different meaning trong ngữ cảnh MongoDB) và nghiêm túc nói rằng không có cách nào được hỗ trợ để lấy lại các tài liệu này - các biện pháp phòng ngừa bạn có thể thực hiện được bao gồm trong các nhận xét. Tuy nhiên, với điều đó nói rằng, nếu bạn đang chạy một bộ bản sao, ngay cả một bản sao nút duy nhất được thiết lập, thì bạn có một oplog. Với oplog bao gồm khi tài liệu được chèn vào, bạn có thể khôi phục chúng.

Cách dễ nhất để minh họa điều này là với ví dụ. Tôi sẽ sử dụng một ví dụ đơn giản chỉ với 100 tài liệu đã bị xóa cần được khôi phục. Để vượt xa điều này (rất nhiều tài liệu, hoặc có lẽ bạn muốn chỉ khôi phục có chọn lọc, vv), bạn sẽ muốn thay đổi mã để lặp qua một con trỏ hoặc viết nó bằng ngôn ngữ bạn chọn ngoài vỏ MongoDB. Logic cơ bản vẫn giữ nguyên.

Trước tiên, hãy tạo bộ sưu tập mẫu của chúng tôi foo trong cơ sở dữ liệu dropTest. Chúng tôi sẽ chèn 100 tài liệu mà không có một lĩnh vực name và 100 tài liệu với một name lĩnh vực giống hệt nhau để họ có thể được nhầm loại bỏ sau:

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"})}; 

Bây giờ, chúng ta hãy mô phỏng việc loại bỏ tình cờ của 100 name văn bản của chúng tôi:

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

Vì chúng tôi đang chạy trong bộ bản sao, chúng tôi vẫn có bản ghi các tài liệu này trong số oplog (đang được chèn) và may mắn là những phần chèn chưa rơi vào cuối oplog (oplogcapped collection nhớ). Hãy xem liệu chúng tôi có thể tìm thấy chúng:

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

Đếm có vẻ chính xác, chúng tôi dường như vẫn có tài liệu của chúng tôi. Tôi biết từ kinh nghiệm rằng mảnh duy nhất của oplog nhập chúng tôi sẽ cần ở đây là lĩnh vực o, vì vậy chúng ta hãy thêm một chiếu chỉ trở lại đó (đầu ra snipped cho ngắn gọn, nhưng bạn sẽ có được ý tưởng):

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" } } 

Để chèn lại các tài liệu đó, chúng ta có thể lưu trữ chúng trong một mảng, sau đó lặp qua mảng và chèn các phần có liên quan.Trước tiên, hãy tạo mảng của chúng tôi:

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

Tiếp theo chúng ta tự nhắc nhở mình rằng chúng tôi chỉ có 100 tài liệu trong bộ sưu tập bây giờ, sau đó vòng qua 100 chèn, và cuối cùng là hợp lệ lại đếm của chúng tôi:

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 

Và có bạn có nó, với một số hãy cẩn thận:

  • này không có nghĩa là một chiến lược phục hồi sự thật, nhìn vào các bản sao lưu (MMS, khác), trì hoãn secondaries cho rằng, như đã đề cập trong các ý kiến ​​
  • Nó sẽ không được đặc biệt nhanh chóng để truy vấn các tài liệu trong số các oplog (bất kỳ truy vấn oplog là một bảng quét) trên một hệ thống bận rộn lớn.
  • Các tài liệu có thể bị loại ra khỏi bất kỳ lúc nào (bạn có thể tạo bản sao của oplog để sử dụng sau này để cung cấp thêm thời gian)
  • Tùy thuộc vào khối lượng công việc bạn có thể phải loại bỏ kết quả trước khi chèn lại chúng
  • Bộ tài liệu lớn hơn sẽ quá lớn đối với mảng như được minh họa, vì vậy bạn sẽ cần phải lặp qua con trỏ thay vì
  • Định dạng của oplog được coi là nội bộ và có thể thay đổi tại bất kỳ thời gian (không cần thông báo), do đó hãy tự chịu rủi ro khi sử dụng
4

Trong khi tôi hiểu điều này là một chút cũ nhưng tôi muốn chia sẻ một cái gì đó mà tôi nghiên cứu trong lĩnh vực này có thể hữu ích cho những người khác với một vấn đề tương tự.

Thực tế là MongoDB không thể xóa dữ liệu ngay lập tức - nó chỉ đánh dấu nó để xóa. Tuy nhiên, đây là phiên bản cụ thể và hiện không có tài liệu hoặc tiêu chuẩn hóa - có thể cho phép nhà phát triển công cụ của bên thứ ba (hoặc ai đó đang cần tuyệt vọng) xây dựng công cụ hoặc viết một kịch bản đơn giản đáng tin cậy hoạt động trên các phiên bản. Tôi đã mở một vé cho việc này - https://jira.mongodb.org/browse/DOCS-5151.

Tôi đã khám phá một tùy chọn ở mức thấp hơn nhiều và có thể cần tinh chỉnh dựa trên phiên bản MongoDB đã sử dụng. Có thể hiểu được mức độ quá thấp đối với liên kết của hầu hết mọi người, tuy nhiên nó hoạt động và có thể thuận tiện khi mọi thứ khác không thành công.

Cách tiếp cận của tôi liên quan trực tiếp đến tệp nhị phân trong tệp và sử dụng tập lệnh Python (hoặc lệnh) để xác định, đọc và giải nén (BSON) dữ liệu đã xóa.

Cách tiếp cận của tôi được lấy cảm hứng từ dự án GitHub this (Tôi KHÔNG phải là nhà phát triển dự án này). Here on my blog Tôi đã cố gắng đơn giản hóa tập lệnh và trích xuất một bản ghi đã xóa cụ thể từ tệp Raw MongoDB.

Hiện tại, bản ghi được đánh dấu để xóa là "\xee" khi bắt đầu bản ghi. Đây là những gì một bản ghi đã xóa trông giống như trong tệp db thô,

‘\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′ 

Tôi đã thay thế khối đầu tiên với kích thước của bản ghi mà tôi đã xác định trước đó dựa trên các bản ghi khác.

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

Cuối cùng sử dụng gói BSON (đi kèm với pymongo), tôi đã giải mã nhị phân thành đối tượng có thể đọc.

bson.decode_all(y) 

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

BSON này bây giờ là một đối tượng python và có thể được đưa vào bộ sưu tập khôi phục hoặc chỉ cần đăng nhập ở đâu đó.

Không cần phải nói điều này hoặc bất kỳ kỹ thuật khôi phục nào khác nên được thực hiện lý tưởng trong khu vực dàn dựng trên bản sao lưu của tệp cơ sở dữ liệu.

+2

Cảm ơn câu trả lời của bạn! Có vẻ như thông tin hiếm có. Sẽ thực sự hữu ích !!. – trex

+0

Chào mừng - Tôi là một phần của bài báo tôi đã viết, tôi cũng đã khám phá cách tôi sẽ làm điều gì đó tương tự với mức độ thành công biến đổi với Apache Cassandra và Apache HBase. –

+2

Tôi đã có một bãi chứa dữ liệu rất lớn để phục hồi, và nắm tay liên kết ở trên không xử lý các bản ghi đã xoá trên Mongo 2.4 đúng như @YazadKhambata đã làm. Vì vậy, tôi viết lại kịch bản trong gist với thông tin của Yazad và nhận được điều này: https://gist.github.com/guss77/f8e610cfddbe02c07896. Tôi đã sử dụng điều này để khôi phục hàng ngàn bản ghi từ một bộ sưu tập lớn đã bị xóa. – Guss

Các vấn đề liên quan