将100万个对象发布到Mongo DB而不会耗尽内存

时间:2016-11-24 12:33:07

标签: javascript node.js mongodb

为了简单起见,我在这里使用了一个for循环来创建一个包含100万个对象的数组。

我想将数组中的每个对象发布到mongo db。

我的记忆力不足。

我知道我可以增加内存分配,但这不是我想要的解决方案。出于超出本示例范围的原因,我也不想使用mongo的批量方法。

我知道必须有一些发布这些对象的方法,这意味着每次迭代都会释放内存(垃圾收集?) - 谁能告诉我它是什么?

谢谢!

此处的当前代码供参考(导致分配错误):

var results = [];

for(var i = 1; i < 1000001; i++){

  results.push({"num":i});

}

async = require("async");
var mongodb = require('mongodb');

var MongoClient = mongodb.MongoClient;
var mongoUrl = 'mongodb://root@localhost:27017/results';

MongoClient.connect(mongoUrl, function (err, db) {

  var collection = db.collection('results');

  // 1st para in async.each() is the array of items
  async.each(results,
    // 2nd param is the function that each item is passed to
    function(item, callback){
      // Call an asynchronous function, often a save() to DB
      collection.insert(item, function (err, result) {
        if(err) console.log(err);
        console.log(item);
        callback();
      });
    },
    // 3rd param is the function to call when everything's done
    function(err){
      // All tasks are done now
      db.close();
    }
  );
});

3 个答案:

答案 0 :(得分:5)

async.each()并行运行插入,因此它基本上启动了1000000个并发插入操作。

您可能希望使用async.eachLimit()

将其限制为100,例如100

答案 1 :(得分:0)

如果要优化插入,请考虑使用bulk operation,因为它还会来回减少网络使用量。同时存储大量数组,特别是如果它们刚刚被计算出来会占用太多内存。

var bulk = collection.initializeUnorderedBulkOp();
var count = 1, i = 0;
var bulkSize = 1000;

var generator = function (mx) {
    if(i < mx){
        return {num: i++}
    }
    return null;
}

var run = function () {
    doc = generator();
    if(doc) {
        bulk.insert(doc)
    }
    if(doc == null || count % bulkSize == 0) {
        bulk.execute(function (err, res) {
            if(err) {} // do something
            if(doc == null) {
                db.close
            }
            run();
        })
    }  
}
run()

此处,程序的任何步骤都不会存储大数组。只有在创建批量数组时,您才会存储它。一旦达到bulkSize

,它也会被刷新到MongoDB

答案 2 :(得分:0)

使用setImmediate来防止内存不足错误

var results = [];

for(var i = 1; i < 1000001; i++){
  results.push({"num":i});
}



run(0, results.length, results, function(err){
    // do stg
});

function run(done, todo, results, callback)
{
    if(++done >= todo)
    {
        // return callback if all done
        return callback(null);
   }
    else
    {
        // save one using index
        //collection.insert(results[done], function(err, res){

       // OR save one and remove it from results
       collection.insert(results.splice(0,1),
            if(err)
                return callback(err);
            else
            {
                // use setImmediate to recall run while releasing stack
                return setImmediate(run, ++done, todo, results, callback);
            }
        });
    }
}