我正在尝试在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")});
答案 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)
作为此主题中提供的答案的补充,我成功了
使用了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+
获得。
我希望这个答案有助于某人。
感谢。