MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Existe-t-il un moyen de récupérer des documents récemment supprimés dans MongoDB ?

Il n'y a pas d'option de restauration (la restauration a une signification différente dans un contexte MongoDB), et à proprement parler, il n'existe aucun moyen pris en charge pour récupérer ces documents - les précautions que vous pouvez/devriez prendre sont couvertes dans les commentaires. Cela dit, cependant, si vous exécutez un jeu de répliques, même un jeu de répliques à un seul nœud, vous avez un oplog . Avec un oplog qui couvre le moment où les documents ont été insérés, vous pourrez peut-être les récupérer.

La façon la plus simple d'illustrer cela est avec un exemple. Je vais utiliser un exemple simplifié avec seulement 100 documents supprimés qui doivent être restaurés. Pour aller au-delà (grand nombre de documents, ou peut-être souhaitez-vous uniquement restaurer de manière sélective, etc.), vous voudrez soit modifier le code pour itérer sur un curseur, soit l'écrire en utilisant le langage de votre choix en dehors du shell MongoDB. La logique de base reste la même.

Commençons par créer notre exemple de collection foo dans la base dropTest . Nous allons insérer 100 documents sans name champ et 100 documents avec un name identique afin qu'ils puissent être supprimés ultérieurement par erreur :

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

Maintenant, simulons la suppression accidentelle de nos 100 name documents :

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

Parce que nous fonctionnons dans un jeu de répliques, nous avons toujours un enregistrement de ces documents dans le oplog (en cours d'insertion) et heureusement, ces insertions ne sont pas (encore) tombées à la fin de l'oplog (l'oplog est une collection plafonnée rappelez-vous) . Voyons si nous pouvons les trouver :

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

Le décompte semble correct, nous semblons avoir encore nos documents. Je sais par expérience que le seul élément de l'oplog l'entrée dont nous aurons besoin ici est le o champ, ajoutons donc une projection pour ne renvoyer que cela (sortie coupée par souci de brièveté, mais vous voyez l'idée):

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

Pour réinsérer ces documents, nous pouvons simplement les stocker dans un tableau, puis parcourir le tableau et insérer les éléments pertinents. Commençons par créer notre tableau :

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

Ensuite, nous nous rappelons que nous n'avons actuellement que 100 documents dans la collection, puis nous parcourons les 100 insertions, et enfin nous revalidons nos décomptes :

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

Et voilà, avec quelques mises en garde :

  • Ce n'est pas censé être une véritable stratégie de restauration, regardez les sauvegardes (MMS, autres), les secondaires retardés pour cela, comme mentionné dans les commentaires
  • Il ne sera pas particulièrement rapide d'interroger les documents hors de l'oplog (toute requête oplog est une analyse de table) sur un grand système occupé.
  • Les documents peuvent vieillir hors de l'oplog à tout moment (vous pouvez, bien sûr, faire une copie de l'oplog pour une utilisation ultérieure pour vous donner plus de temps)
  • Selon votre charge de travail, vous devrez peut-être dédupliquer les résultats avant de les réinsérer
  • De plus grands ensembles de documents seront trop volumineux pour un tableau, comme illustré, vous devrez donc itérer sur un curseur à la place
  • Le format de l'oplog est considéré comme interne et peut changer à tout moment (sans préavis), utilisez-le donc à vos risques et périls