restaurar - respaldo y restauracion de mongodb
¿Hay alguna forma de recuperar documentos borrados recientemente en MongoDB? (2)
No hay opción de reversión (la reversión tiene un significado diferente en un contexto de MongoDB) y, estrictamente hablando, no hay una forma compatible de recuperar estos documentos: las precauciones que puede / debe tomar están cubiertas 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 cuando se insertaron los documentos, puede 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 quizás desee restaurar solo de manera selectiva, etc.), querrá cambiar el código para iterar sobre un cursor o escribirlo usando el idioma que elija fuera del shell MongoDB. La lógica básica sigue siendo la misma.
Primero, dropTest
nuestra colección de ejemplos foo
en la base de datos dropTest
. Insertaremos 100 documentos sin un campo de name
y 100 documentos con un campo de name
idéntico para que puedan eliminarse por error más adelante:
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 nuestros 100 documentos de name
:
> db.foo.remove({ "name" : "some_x_name"})
WriteResult({ "nRemoved" : 100 })
Debido a que nos estamos ejecutando en un conjunto de réplicas, todavía tenemos un registro de estos documentos en el oplog
(se está insertando) y, afortunadamente, esas inserciones aún no se han desprendido del final del oplog
(el oplog
es una colección con límite ). A ver 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 parte de la entrada de oplog
que necesitaremos aquí es el campo o
, así que agreguemos una proyección para devolver solo eso (salida cortada por brevedad, pero se tiene 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, solo podemos almacenarlos en una matriz, luego iterar sobre la matriz e insertar las piezas relevantes. Primero, vamos a crear 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, nos recordamos a nosotros mismos que ahora solo tenemos 100 documentos en la colección, luego repasamos las 100 inserciones y finalmente revalidamos nuestros conteos:
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 tienen, con algunas advertencias:
- Esto no pretende ser una verdadera estrategia de restauración, ver copias de seguridad (MMS, otros), secundarios retrasados para eso, como se menciona en los comentarios
- No va a ser particularmente rápido consultar los documentos fuera del oplog (cualquier consulta de oplog es un escaneo de tablas) en un sistema grande y ocupado.
- Los documentos pueden caducar fuera del oplog en cualquier momento (puede, por supuesto, hacer una copia del oplog para su uso posterior para darle más tiempo)
- Dependiendo de su carga de trabajo, es posible que tenga que reducir 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 tendrá que iterar sobre un cursor.
- El formato del
oplog
se considera interno y puede cambiar en cualquier momento (sin previo aviso), así queoplog
bajo su propio riesgo
He eliminado algunos documentos en mi última consulta por error. ¿Hay alguna forma de revertir mi última colección de mongo de consultas?
Aquí está mi última consulta:
db.datas.remove({ "name" : "some_x_name"})
¿Hay alguna opción de deshacer / deshacer? ¿Puedo recuperar mis datos?
Si bien entiendo que esto es un poco viejo, quería compartir algo que he investigado en esta área que puede ser útil para otros con un problema similar.
El hecho es que MongoDB no elimina Físicamente los datos inmediatamente, solo los marca para eliminarlos. Sin embargo, esta es una versión específica y actualmente no hay documentación o estandarización, lo que podría permitir a un desarrollador de herramientas de terceros (o alguien con una necesidad desesperada) construir una herramienta o escribir un script simple que funcione en todas las versiones. Abrí un boleto para esto - https://jira.mongodb.org/browse/DOCS-5151 .
Exploré una opción que se encuentra en un nivel mucho más bajo y puede que necesite un ajuste fino en función de la versión de MongoDB utilizada. Comprensiblemente, un nivel demasiado bajo para la mayoría de los enlaces de personas, sin embargo, funciona y puede ser útil cuando todo lo demás falla.
Mi enfoque implica trabajar directamente con el binario en el archivo y usar un script de Python (o comandos) para identificar, leer y desempaquetar (BSON) los datos eliminados.
Mi enfoque está inspirado en this proyecto de GitHub (NO soy el desarrollador de este proyecto). Aquí, en mi blog , he intentado simplificar el script y extraer un registro específico eliminado de un archivo Raw MongoDB.
Actualmente, un registro está marcado para su eliminación como " /xee
" al comienzo del registro. Así es como se ve un registro eliminado en el archivo db en bruto,
‘/xee/xee/xee/xee/x07_id/x00U/x19/xa6g/x9f/xdf/x19/xc1/xads/xdb/xa8/x02name/x00/x04/x00/x00/x00AAA/x00/x01marks/x00/x00/x00/x00/x00/x00@/x9f@/x00′
Reemplacé el primer bloque con el tamaño del registro que identifiqué anteriormente en base a otros registros.
y=”3/x00/x00/x00″+x[20804:20800+51]
Finalmente, utilizando el paquete BSON (que viene con pymongo), descodifiqué el binario a un objeto de lectura.
bson.decode_all(y)
[{u’_id'': ObjectId(‘5519a6679fdf19c1ad73dba8′), u’name'': u’AAA’, u’marks'': 2000.0}]
Este BSON ahora es un objeto de Python y puede volcarse en una colección de recuperación o simplemente registrarse en algún lugar.
No hace falta decir que esta o cualquier otra técnica de recuperación se debe realizar idealmente en un área de almacenamiento en una copia de respaldo del archivo de la base de datos.