Nie ma opcji wycofania (cofanie ma inne znaczenie w kontekście MongoDB) i ściśle mówiąc, nie ma obsługiwanego sposobu na odzyskanie tych dokumentów - środki ostrożności, które możesz/należy podjąć, są opisane w komentarzach. Mając to na uwadze, jeśli używasz zestawu replik, nawet zestawu replik z jednym węzłem, masz oplog
. Z oplog
który obejmuje czas włożenia dokumentów, możesz je odzyskać.
Najłatwiej to zilustrować przykładem. Posłużę się uproszczonym przykładem z zaledwie 100 usuniętymi dokumentami, które należy przywrócić. Aby wyjść poza to (ogromna liczba dokumentów, a może chcesz tylko selektywnie przywracać itp.), będziesz chciał zmienić kod, aby iterować po kursorze lub napisać to w wybranym języku poza powłoką MongoDB. Podstawowa logika pozostaje taka sama.
Najpierw utwórzmy naszą przykładową kolekcję foo
w bazie danych dropTest
. Wstawimy 100 dokumentów bez name
pole i 100 dokumentów z identyczną name
pole, aby można je było później omyłkowo usunąć:
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"})};
Teraz zasymulujmy przypadkowe usunięcie naszych 100 name
dokumenty:
> db.foo.remove({ "name" : "some_x_name"})
WriteResult({ "nRemoved" : 100 })
Ponieważ działamy w zestawie replik, nadal mamy zapis tych dokumentów w oplog
(jest wstawiane) i na szczęście te wstawki nie spadły (jeszcze) z końca oplog
(oplog
to kolekcja ograniczona, pamiętaj) . Zobaczmy, czy uda nam się je znaleźć:
use local;
db.oplog.rs.find({op : "i", ns : "dropTest.foo", "o.name" : "some_x_name"}).count();
100
Liczenie wygląda poprawnie, wydaje się, że nadal mamy nasze dokumenty. Z doświadczenia wiem, że jedyny fragment oplog
będziemy tu potrzebować wpisu o
pole, więc dodajmy projekcję, która tylko to zwróci (wyjście obcięte dla zwięzłości, ale masz pomysł):
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" } }
Aby ponownie wstawić te dokumenty, możemy po prostu przechowywać je w tablicy, a następnie iterować po tablicy i wstawiać odpowiednie fragmenty. Najpierw utwórzmy naszą tablicę:
var deletedDocs = db.oplog.rs.find({op : "i", ns : "dropTest.foo", "o.name" : "some_x_name"}, {"o" : 1}).toArray();
> deletedDocs.length
100
Następnie przypominamy sobie, że mamy teraz w kolekcji tylko 100 dokumentów, potem wykonujemy pętlę nad 100 wstawkami, a na koniec ponownie sprawdzamy nasze obliczenia:
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
I masz to, z pewnymi zastrzeżeniami:
- To nie ma być prawdziwa strategia przywracania, spójrz na kopie zapasowe (MMS, inne), opóźnione wtórne, jak wspomniano w komentarzach
- Nie będzie szczególnie szybkie wyszukiwanie dokumentów z oploga (każde zapytanie oploga to skanowanie tabeli) w dużym, obciążonym systemie.
- Dokumenty mogą w dowolnym momencie przestać działać w oplogu (oczywiście możesz zrobić kopię oploga do późniejszego wykorzystania, aby dać ci więcej czasu)
- W zależności od obciążenia pracą może być konieczne usunięcie duplikatów wyników przed ich ponownym wstawieniem
- Większe zestawy dokumentów będą zbyt duże dla tablicy, jak pokazano, więc zamiast tego będziesz musiał iterować po kursorze
- Format
oplog
jest uważany za wewnętrzny i może ulec zmianie w dowolnym momencie (bez powiadomienia), więc używaj go na własne ryzyko