从MongoDB中删除大量数据

时间:2017-07-11 22:33:50

标签: mongodb database

我有以下可用的代码。它遍历并找到比指定日期更新并且与正则表达式匹配的每个文件,然后删除它,以及指向它的块。

conn = new Mongo("<url>");
db = conn.getDB("<project>");

res = db.fs.files.find({"uploadDate" : { $gte : new ISODate("2017-04-04")}}, {filename : /.*(png)/});
while (res.hasNext()) {
    var tmp = res.next();
    db.getCollection('fs.chunks').remove({"files_id" : tmp._id});
    db.fs.files.remove({ "_id" : tmp._id});
}

这是非常缓慢的,而且大部分时间,客户端我都是在短时间内运行它。

另外,我知道我正在从文件系统中删除文件,而不是从正常的集合中删除。这是一个很长的故事,但上面的代码完全符合我的要求。

如何让它更快地运行? 我之前曾向我指出,我在客户端上运行此代码,但是可以在服务器端运行它吗?在我尝试使用Javascript驱动程序之前,这可能就是为什么。我假设使用Mongo shell在服务器上执行everythin。

任何帮助将不胜感激。如此接近,但到目前为止......

1 个答案:

答案 0 :(得分:2)

  

我知道我正在从文件系统中删除文件,而不是从正常的集合中删除文件

GridFS是用于在MongoDB中存储二进制数据的规范,因此您实际上是从MongoDB集合中删除文档而不是从文件系统中删除文件。

  

我之前曾向我指出,我在客户端上运行此代码,但是可以在服务器端运行它吗?

您的MongoDB服务器正在执行您的大部分代码(查询和命令)。客户端(在这种情况下为mongo shell)没有进行任何重要的处理。

  

这是非常缓慢的,而且大部分时间,客户端我都是在短时间内运行它。

您需要调查花费的时间。

如果您的mongo shell与部署之间存在网络延迟问题,则可以考虑从靠近部署的mongo shell会话运行查询(如果可能)或使用与较小范围的文件。

另一个值得研究的明显候选者是服务器资源。例如,删除大量文件会对I / O或RAM造成压力吗?在这种情况下,减少在每个脚本运行中删除的文档数量也可能有所帮助。

  

db.fs.files.find({“uploadDate”:{$ gte:new ISODate(“2017-04-04”)}},{filename:/.*(png)/})

此查询可能没有按预期执行:filename作为find()的第二个选项提供(因此用于投影而不是搜索条件)并且正则表达式匹配文件名在任何地方都包含png(例如:typng.doc)。

  

我假设使用Mongo shell在服务器上执行everythin。

这是一个不正确的一般假设。 mongo shell可以评估本地函数,因此根据您的代码,可能存在在客户端上下文而不是服务器上下文中执行/评估的方面。您的示例代码正在运行在服务器上处理的查询/命令,但正在fs.files shell中访问find()查询返回的mongo文档,以便构造要删除的查询fs.chunks中的相关文件。

  

如何让它更快地运行?

除了上面提到的评论之外,您还可以进行一些代码更改以提高效率。特别是,您当前正在单独删除块文档。 MongoDB 2.6+中有Bulk API,这将减少每批删除所需的往返次数。

尝试提高速度的其他一些建议:

  • {uploadDate:1, filename: 1}上添加索引以支持您的find()查询:

    db.fs.files.createIndex({uploadDate:1, filename: 1})
    
  • 使用批量API删除匹配的块文档而不是单个删除:

    while (res.hasNext()) {
        var tmp = res.next();
        var bulk = db.fs.chunks.initializeUnorderedBulkOp();
        bulk.find( {"files_id" : tmp._id} ).remove();
        bulk.execute();
        db.fs.files.remove({ "_id" : tmp._id});
    }
    
  • fs.files查询添加投影,仅包含您需要的字段:

    var res = db.fs.files.find(
       // query criteria
       {
           uploadDate: { $gte: new ISODate("2017-04-04") },
    
           // Filenames that end in png
           filename: /\.png$/
       },
    
       // Only include the _id field
       { _id: 1 }
    )
    

    注意:除非您在GridFS文件中添加了大量元数据(或者要删除大量文件),否则这可能不会产生重大影响。默认的fs.files文档大约是130个字节,但是您需要的唯一字段是_id(12字节的ObjectId)。