sql >> Base de Datos >  >> NoSQL >> MongoDB

¿Hay alguna forma de recuperar documentos eliminados recientemente en MongoDB?

No hay una opción de reversión (la reversión tiene un significado diferente en un contexto de MongoDB) y, estrictamente hablando, no existe una forma admitida de recuperar estos documentos:las precauciones que puede/debe tomar se describen en los comentarios. Sin embargo, dicho esto, si está ejecutando un conjunto de réplicas, incluso un conjunto de réplicas de un solo nodo, entonces tiene un oplog . Con un oplog que cubre cuándo se insertaron los documentos, es posible que pueda recuperarlos.

La forma más fácil de ilustrar esto es con un ejemplo. Usaré un ejemplo simplificado con solo 100 documentos eliminados que deben restaurarse. Para ir más allá de esto (gran cantidad de documentos, o tal vez solo desea restaurar selectivamente, etc.), querrá cambiar el código para iterar sobre un cursor o escribirlo usando el idioma de su elección fuera del shell de MongoDB. La lógica básica sigue siendo la misma.

Primero, creemos nuestra colección de ejemplo foo en la base de datos dropTest . Insertaremos 100 documentos sin name campo y 100 documentos con un name idéntico campo para que puedan ser eliminados por error más tarde:

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

Ahora, simulemos la eliminación accidental de nuestro 100 name documentos:

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

Debido a que estamos ejecutando un conjunto de réplicas, todavía tenemos un registro de estos documentos en el oplog (siendo insertado) y afortunadamente esos insertos (todavía) no se han caído del final del oplog (el oplog es una colección tapada recuerda) . Veamos si podemos encontrarlos:

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

El conteo parece correcto, parece que todavía tenemos nuestros documentos. Sé por experiencia que la única pieza del oplog la entrada que necesitaremos aquí es o campo, así que agreguemos una proyección para devolver solo eso (salida recortada por brevedad, pero se entiende la idea):

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

Para volver a insertar esos documentos, podemos simplemente almacenarlos en una matriz, luego iterar sobre la matriz e insertar las piezas relevantes. Primero, creemos nuestra matriz:

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

A continuación, recordamos que ahora solo tenemos 100 documentos en la colección, luego repasamos las 100 inserciones y finalmente revalidamos nuestros recuentos:

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

Y ahí lo tienes, con algunas salvedades:

  • Esto no pretende ser una verdadera estrategia de restauración, mire las copias de seguridad (MMS, otras), las secundarias retrasadas para eso, como se menciona en los comentarios
  • No será particularmente rápido consultar los documentos del registro de operaciones (cualquier consulta de registro de operaciones es un escaneo de tabla) en un sistema grande y ocupado.
  • Los documentos pueden quedar obsoletos del oplog en cualquier momento (por supuesto, puede hacer una copia del oplog para usarla más adelante y tener más tiempo)
  • Dependiendo de su carga de trabajo, es posible que deba eliminar los duplicados de los resultados antes de volver a insertarlos
  • Los conjuntos de documentos más grandes serán demasiado grandes para una matriz como se muestra, por lo que deberá iterar sobre un cursor
  • El formato del oplog se considera interno y puede cambiar en cualquier momento (sin previo aviso), así que utilícelo bajo su propio riesgo