如何从node.js转储mongodb中的大型数据集

时间:2015-11-10 09:52:19

标签: node.js mongodb mongoose

我正在尝试在mongodb中转储大约220万个对象(使用mongoose)。问题是当我逐个保存所有对象时它会卡住。我在下面给出了一个示例代码。如果我运行此代码为50,000,它的效果很好。但是如果我将数据大小增加到大约500,000就会卡住。我想知道这种方法有什么问题,我想找到一个更好的方法来做到这一点。我对nodejs很新。我试过循环,一切都没有帮助,我终于找到了这种解决方案。这个适用于50k物体,但却被220万个物体卡住了。我会在一段时间后得到这个

致命错误:CALL_AND_RETRY_2分配失败 - 处理内存不足 中止(核心倾销)

var connection = mongoose.createConnection("mongodb://localhost/entity");
var entitySchema = new mongoose.Schema({
 name: String
 , date: Date
 , close : Number
 , volume: Number
 , adjClose: Number
  });

 var Entity = connection.model('entity', entitySchema)
    var mongoobjs =["2.2 Millions obejcts here populating in code"] // works completely fine till here

    async.map(mongoobjs, function(object, next){

        Obj = new Entity({
        name : object.name
      , date: object.date
      , close : object.close
      , volume: object.volume
      , adjClose: object.adjClose
    });
    Obj.save(next);


}, function(){console.log("Saved")});

3 个答案:

答案 0 :(得分:1)

谢谢cdbajorin

这似乎是更好的方法和更快的批处理方法来做到这一点。所以我学到的是在我之前的方法中,"新的实体(......)"花时间并导致内存溢出。仍不确定原因。

所以,我所做的不是使用这一行

 Obj = new Entity({
    name : object.name
  , date: object.date
  , close : object.close
  , volume: object.volume
  , adjClose: object.adjClose
});

我刚创建了JSON对象并存储在数组中。

stockObj ={
    name : object.name
  , date: object.date
  , close : object.close
  , volume: object.volume
  , adjClose: object.adjClose
};
   mongoobjs.push(stockObj); //array of objs.

并使用了这个命令......和Voila一起工作!!!

Entity.collection.insert(mongoobjs, function(){ console.log("Saved succesfully")});

答案 1 :(得分:0)

nodejs使用v8,它具有不幸的属性,从开发人员来自其他解释语言的角度来看,无论可用的系统内存如何,都会严重限制你可以使用的内存量为1.7GB。

实际上只有一种方法可以解决这个问题 - 使用流。确切地说,如何做到这一点取决于你。例如,您可以简单地连续流式传输数据,在数据进入时对其进行处理,并让处理后的对象进行垃圾回收。这具有难以平衡输入与输出的缺点。

我们最近一直偏爱的方法是让输入流带来工作并将其保存到队列(例如阵列)。与此同时,您可以编写一个始终尝试将工作从队列中拉出来的函数。这样可以很容易地分离逻辑并限制输入流,以防工作进入(或离开)太快。

例如,假设为了避免内存问题,您希望在队列中保留低于50k的对象。如果输出队列具有>那么您的流入功能可以暂停流或跳过get()调用。 50k条目。同样,您可能希望批量写入以提高服务器效率。所以你的输出处理器可以避免写入,除非队列中至少有500个对象,或者自上次写入以来它已超过1秒。

这是有效的,因为javascript使用event loop,这意味着它将自动在异步任务之间切换。节点将数据流传输一段时间,然后切换到另一个任务。您可以使用setTimeout()setInterval()来确保函数调用之间存在一些延迟,从而允许其他异步任务恢复。

专门解决您的问题,看起来您正在单独保存每个对象。这需要很长时间才能完成220万个对象。相反,必须有一种批量写入的方法。

答案 2 :(得分:0)

作为此主题中提供的答案的补充,我成功了

  • 批量插入(或批量插入)20.000+文档(或对象)
  • 在Heroku的廉价产品中使用低内存(250 MB)
  • 使用一个实例,无需任何并行处理

使用了MongoDB本机驱动程序指定的批量操作,以下是适用于我的代码:

var counter = 0;
var entity= {}, entities = [];// Initialize Entities from a source such as a file, external database etc
var bulk = Entity.collection.initializeOrderedBulkOp();
var size = MAX_ENTITIES; //or `entities.length` Defined in config, mine was 20.0000 
//while and -- constructs is deemed faster than other loops available in JavaScript ecosystem
while(size--){
    entity = entities[size];
    if( entity && entity.id){
        // Add `{upsert:true}` parameter to create if object doesn't exist
         bulk.find({id: entity.id}).update({$set:{value:entity.value}});
    }
    console.log('processing --- ', entity, size);
}
bulk.execute(function (error) {
    if(error) return next(error);
    return next(null, {message: 'Synced vector data'});                 
});

实体是一种猫鼬模型。 旧版mongodb可能不支持Entity类型,因为它可以从version 3+获得。

我希望这个答案有助于某人。

感谢。

相关问题