Mongodb缓慢更新循环

问题描述:

我刚刚熟悉Mongodb,这就是为什么我做了一些愚蠢的事情。我的每个数据集的条目都包含一个时间戳(他们是Tweets)。我没有在插入之前将时间戳从字符串转换为实际日期格式,而是将其简单插入为字符串。Mongodb缓慢更新循环

现在,我的数据集变得非常庞大(超过3百万条推文),我想开始排序/排列我的条目。由于我的时间戳仍然是一个字符串(“Wed Apr 29 09:52:22 +0000 2015”),我想将其转换为日期格式。

我发现这个答案下面的代码: How do I convert a property in MongoDB from text to date type?

> var cursor = db.ClockTime.find() 
> while (cursor.hasNext()) { 
... var doc = cursor.next(); 
... db.ClockTime.update({_id : doc._id}, {$set : {ClockInTime : new Date(doc.ClockInTime)}}) 
... } 

而且它的伟大工程。然而,这是非常缓慢的。根据MongoHub应用程序,它每秒只处理4个查询。使用300万推文的数据集,这将需要大约8.6天的时间进行转换。我真的希望有一种方法可以加快速度,因为我的截止日期是8天:P

有什么想法?

+2

看看这个[文章](https://midnightcodr.github.io/2014/11/22/How-to-convert-20-million-datetime-strings-to-ISODate-in-less-比-30分钟/) – Yogesh

+0

这似乎很有前途,谢谢! – Diederik

默认情况下,更新阻塞,直到数据库发回确认成功执行更新为止。当您在本地工作站上使用mongo shell并连接到远程数据库时,这至少需要ping到数据库。

如果允许,可以通过SSH连接到数据库服务器(副本集的主服务器)并在其中运行脚本。这将网络延迟减少到几乎为零。当你有一个集群时,结果可能仍然是一个改进,但并不是那么多,因为你需要登录到mongos服务器,它仍然需要等待来自其更新路由的副本集的确认, 。

另一种选择是执行更新,不写入关注。程序执行将立即继续,这将大大提高速度。但请记住,这种方式会忽略任何错误。

db.ClockTime.update(
    {_id : doc._id}, 
    {$set : {ClockInTime : new Date(doc.ClockInTime)}}, 
    {writeConcern: {w: 0}} 
) 

这将是更快的第三种选择是使用mongoexport得到JSON格式的所有收藏的文件导出,与当地的脚本转换它,然后用mongoimport重新导入的转换数据。缺点是如果在导出和导入之间没有很短的停机时间,您将无法做到这一点,因为它们之间的任何数据都将丢失。

+0

谢谢你这个详细的答案!事实上,登录到SSH服务器的速度相当快,解决了问题,没有数据丢失,因为我不必导出/导入数据库。 – Diederik

另一种选择是使用批量操作,这是非常快的,尤其是the unordered variant,因为它们可以并行应用。

var bulk = db.ClockTime.initializeUnorderedBulkOp() 
var myDocs = db.ClockTime.find() 

var ops = 0 

myDocs.forEach(

    function(myDoc) { 

    bulk.find(
     {_id:myDoc._id} 
    ).updateOne(
     {$set : { ClockInTime: new Date(myDoc.ClockInTime) } } 
    ); 

    if ((++ops % 10000) === 0){ 
     bulk.execute(); 
     bulk = db.ClockTime.initializeUnorderedBulkOp(); 
    } 

    } 
bulk.execute() 
)