Tidak ada opsi rollback (rollback memiliki arti yang berbeda dalam konteks MongoDB), dan sebenarnya tidak ada cara yang didukung untuk mendapatkan kembali dokumen-dokumen ini - tindakan pencegahan yang dapat/harus Anda ambil tercakup dalam komentar. Namun demikian, jika Anda menjalankan set replika, bahkan set replika node tunggal, maka Anda memiliki oplog
. Dengan oplog
yang mencakup saat dokumen dimasukkan, Anda mungkin dapat memulihkannya.
Cara termudah untuk menggambarkan ini adalah dengan sebuah contoh. Saya akan menggunakan contoh sederhana dengan hanya 100 dokumen terhapus yang perlu dipulihkan. Untuk melampaui ini (sejumlah besar dokumen, atau mungkin Anda hanya ingin memulihkan secara selektif, dll.), Anda ingin mengubah kode untuk mengulangi kursor atau menulis ini menggunakan bahasa pilihan Anda di luar shell MongoDB. Logika dasarnya tetap sama.
Pertama, mari kita buat koleksi contoh kita foo
dalam database dropTest
. Kami akan memasukkan 100 dokumen tanpa name
bidang dan 100 dokumen dengan name
yang identik bidang sehingga nanti bisa salah dihapus:
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"})};
Sekarang, mari simulasikan penghapusan tidak sengaja dari 100 name
dokumen:
> db.foo.remove({ "name" : "some_x_name"})
WriteResult({ "nRemoved" : 100 })
Karena kami menjalankan dalam set replika, kami masih memiliki catatan dokumen-dokumen ini di oplog
(sedang dimasukkan) dan untungnya sisipan itu belum (belum) jatuh dari akhir oplog
(oplog
adalah koleksi yang dibatasi ingat). Mari kita lihat apakah kita dapat menemukannya:
use local;
db.oplog.rs.find({op : "i", ns : "dropTest.foo", "o.name" : "some_x_name"}).count();
100
Hitungannya terlihat benar, kami sepertinya masih memiliki dokumen kami. Saya tahu dari pengalaman bahwa satu-satunya bagian dari oplog
entri yang kita perlukan di sini adalah o
bidang, jadi mari tambahkan proyeksi untuk mengembalikannya saja (keluaran dipotong untuk singkatnya, tetapi Anda mendapatkan idenya):
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" } }
Untuk menyisipkan kembali dokumen-dokumen itu, kita cukup menyimpannya dalam sebuah array, lalu mengulanginya di atas array dan menyisipkan bagian-bagian yang relevan. Pertama, mari kita buat array kita:
var deletedDocs = db.oplog.rs.find({op : "i", ns : "dropTest.foo", "o.name" : "some_x_name"}, {"o" : 1}).toArray();
> deletedDocs.length
100
Selanjutnya kami mengingatkan diri kami sendiri bahwa kami hanya memiliki 100 dokumen dalam koleksi sekarang, lalu mengulang 100 sisipan, dan akhirnya memvalidasi ulang jumlah kami:
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
Dan begitulah, dengan beberapa peringatan:
- Ini tidak dimaksudkan sebagai strategi pemulihan yang sebenarnya, lihat cadangan (MMS, lainnya), sekunder yang tertunda untuk itu, seperti yang disebutkan dalam komentar
- Tidak akan terlalu cepat untuk mengkueri dokumen dari oplog (setiap kueri oplog adalah pemindaian tabel) pada sistem besar yang sibuk.
- Dokumen dapat usang dari oplog kapan saja (Anda tentu saja dapat membuat salinan oplog untuk digunakan nanti guna memberi Anda lebih banyak waktu)
- Bergantung pada beban kerja Anda, Anda mungkin harus menghapus hasil penipuan sebelum memasukkannya kembali
- Kumpulan dokumen yang lebih besar akan terlalu besar untuk array seperti yang ditunjukkan, jadi Anda perlu mengulangi kursor sebagai gantinya
- Format
oplog
dianggap internal dan dapat berubah sewaktu-waktu (tanpa pemberitahuan), jadi gunakan dengan risiko Anda sendiri