Er is geen terugdraaioptie (terugdraaien heeft een andere betekenis in een MongoDB-context), en strikt genomen is er geen ondersteunde manier om deze documenten terug te krijgen - de voorzorgsmaatregelen die u kunt/moet nemen worden behandeld in de opmerkingen. Dat gezegd hebbende, als je een replicaset gebruikt, zelfs een replicaset met een enkel knooppunt, dan heb je een oplog
. Met een oplog
die dekt toen de documenten werden ingevoegd, kunt u ze mogelijk herstellen.
De eenvoudigste manier om dit te illustreren is met een voorbeeld. Ik zal een vereenvoudigd voorbeeld gebruiken met slechts 100 verwijderde documenten die moeten worden hersteld. Om verder te gaan (groot aantal documenten, of misschien wilt u alleen selectief herstellen, enz.) U wilt ofwel de code wijzigen om over een cursor te itereren of dit schrijven met uw taal naar keuze buiten de MongoDB-shell. De basislogica blijft hetzelfde.
Laten we eerst onze voorbeeldverzameling foo
. maken in de database dropTest
. We zullen 100 documenten invoegen zonder een name
veld en 100 documenten met een identieke name
veld zodat ze later per ongeluk kunnen worden verwijderd:
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"})};
Laten we nu de onopzettelijke verwijdering van onze 100 name
. simuleren documenten:
> db.foo.remove({ "name" : "some_x_name"})
WriteResult({ "nRemoved" : 100 })
Omdat we in een replicaset werken, hebben we nog steeds een record van deze documenten in de oplog
(wordt ingevoegd) en gelukkig zijn die inserts (nog) niet van het einde van de oplog
gevallen (de oplog
is een afgetopte collectie onthoud). Eens kijken of we ze kunnen vinden:
use local;
db.oplog.rs.find({op : "i", ns : "dropTest.foo", "o.name" : "some_x_name"}).count();
100
De telling ziet er goed uit, we lijken onze documenten nog te hebben. Ik weet uit ervaring dat het enige stukje van de oplog
invoer die we hier nodig hebben is de o
veld, dus laten we een projectie toevoegen om alleen dat terug te geven (uitvoer voor de beknoptheid geknipt, maar je snapt het idee):
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" } }
Om die documenten opnieuw in te voegen, kunnen we ze gewoon in een array opslaan, vervolgens de array herhalen en de relevante stukken invoegen. Laten we eerst onze array maken:
var deletedDocs = db.oplog.rs.find({op : "i", ns : "dropTest.foo", "o.name" : "some_x_name"}, {"o" : 1}).toArray();
> deletedDocs.length
100
Vervolgens herinneren we onszelf eraan dat we nu slechts 100 documenten in de collectie hebben, lopen dan de 100 bijlagen door en valideren tenslotte onze tellingen:
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
En daar heb je het, met enkele kanttekeningen:
- Dit is niet bedoeld als een echte herstelstrategie, kijk naar back-ups (MMS, andere), vertraagde secundairen daarvoor, zoals vermeld in de opmerkingen
- Het zal niet bijzonder snel zijn om de documenten uit de oplog op te vragen (elke oplog-query is een tabelscan) op een groot druk systeem.
- De documenten kunnen op elk moment uit de oplog komen te vervallen (u kunt natuurlijk een kopie van de oplog maken voor later gebruik om u meer tijd te geven)
- Afhankelijk van uw werklast moet u mogelijk de resultaten ontdubbelen voordat u ze opnieuw invoegt
- Grotere sets documenten zullen te groot zijn voor een array, zoals aangetoond, dus u moet in plaats daarvan over een cursor heen gaan
- Het formaat van de
oplog
wordt als intern beschouwd en kan op elk moment veranderen (zonder kennisgeving), dus gebruik op eigen risico