有什么办法可以恢复MongoDB中最近删除的文档? [英] Is there any way to recover recently deleted documents in MongoDB?

查看:198
本文介绍了有什么办法可以恢复MongoDB中最近删除的文档?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我错误地删除了上一个查询中的一些文档,有没有办法回滚我的上一个查询mongo集合.

I have removed some documents in my last query by mistake, Is there any way to rollback my last query mongo collection.

这是我的最后一个查询:

Here it is my last query :

 db.foo.remove({ "name" : "some_x_name"}) 

是否有任何回滚/撤消选项?我可以取回我的数据吗?

Is there any rollback/undo option? Can I get my data back?

推荐答案

没有回滚选项(回滚在MongoDB上下文中具有不同的含义),严格来说,没有支持将这些文档取回的方法-注释中涵盖了您可以/应该采取的预防措施.话虽如此,如果您正在运行副本集,甚至是单节点副本集,那么您的

There is no rollback option (rollback has a different meaning in a MongoDB context), and strictly speaking there is no supported way to get these documents back - the precautions you can/should take are covered in the comments. With that said however, if you are running a replica set, even a single node replica set, then you have an oplog. With an oplog that covers when the documents were inserted, you may be able to recover them.

最简单的方法是举一个例子.我将使用一个简化的示例,其中仅包含100个需要还原的已删除文档.要超越此限制(大量文档,或者您可能只希望选择性地还原等),您可能想要更改代码以遍历游标,或者在MongoDB Shell之外使用您选择的语言编写此代码.基本逻辑保持不变.

The easiest way to illustrate this is with an example. I will use a simplified example with just 100 deleted documents that need to be restored. To go beyond this (huge number of documents, or perhaps you wish to only selectively restore etc.) you will either want to change the code to iterate over a cursor or write this using your language of choice outside the MongoDB shell. The basic logic remains the same.

首先,让我们在数据库dropTest中创建示例集合foo.我们将插入100个不带name字段的文档,并插入100个具有相同name字段的文档,以便以后可以将它们错误地删除:

First, let's create our example collection foo in the database dropTest. We will insert 100 documents without a name field and 100 documents with an identical name field so that they can be mistakenly removed later:

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

现在,让我们模拟一下意外删除100个name文档的情况:

Now, let's simulate the accidental removal of our 100 name documents:

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

由于我们在副本集中运行,因此我们仍然在oplog中记录了这些文档(正在插入),并且值得庆幸的是,这些插入还没有(还)落在oplog的末尾(oplog上限集合记住).让我们看看是否可以找到它们:

Because we are running in a replica set, we still have a record of these documents in the oplog (being inserted) and thankfully those inserts have not (yet) fallen off the end of the oplog (the oplog is a capped collection remember) . Let's see if we can find them:

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

计数似乎正确,我们似乎仍在保存文件.从经验中我知道,我们在这里需要的oplog条目唯一的部分是o字段,所以让我们添加一个投影以仅返回该投影(为简洁起见,输出被删减了,但您知道了):

The count looks correct, we seem to have our documents still. I know from experience that the only piece of the oplog entry we will need here is the o field, so let's add a projection to only return that (output snipped for brevity, but you get the 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" } }

要重新插入这些文档,我们可以将它们存储在一个数组中,然后遍历该数组并插入相关的片段.首先,让我们创建数组:

To re-insert those documents, we can just store them in an array, then iterate over the array and insert the relevant pieces. First, let's create our array:

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

接下来,我们提醒自己,现在集合中只有100个文档,然后循环遍历100个插入,最后重新验证计数:

Next we remind ourselves that we only have 100 docs in the collection now, then loop over the 100 inserts, and finally revalidate our counts:

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

在这里,有一些警告:

  • 这并不意味着它是真正的恢复策略,请查看备份(MMS,其他),为此延迟备份,如评论中所述
  • 在大型繁忙的系统上从oplog(任何oplog查询都是表扫描)中查询文档并不是特别快.
  • 文档可能会随时在oplog中过期(当然,您可以复制oplog以便以后使用,以给您更多时间)
  • 根据您的工作量,您可能必须在重复插入结果之前对结果进行重复数据删除
  • 如所示,较大的文档集对于数组而言太大,因此您需要遍历游标
  • oplog的格式被认为是内部格式,可能随时更改(恕不另行通知),因此使用后果自负
  • This is not meant to be a true restoration strategy, look at backups (MMS, other), delayed secondaries for that, as mentioned in the comments
  • It's not going to be particularly quick to query the documents out of the oplog (any oplog query is a table scan) on a large busy system.
  • The documents may age out of the oplog at any time (you can, of course, make a copy of the oplog for later use to give you more time)
  • Depending on your workload you might have to de-dupe the results before re-inserting them
  • Larger sets of documents will be too large for an array as demonstrated, so you will need to iterate over a cursor instead
  • The format of the oplog is considered internal and may change at any time (without notice), so use at your own risk

这篇关于有什么办法可以恢复MongoDB中最近删除的文档?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆