插入文档循环 - RangeError:超出最大调用堆栈大小

时间:2014-08-10 22:12:51

标签: javascript node.js mongodb mongoose

我实际上是使用node和mongodb给出了我的第一步,我最近遇到了这个RangeError墙。

这是我想要做的,我有一个文件,其中包含我想要添加到我的mongo db的国家/地区列表。这将是我的种子"的一部分。使应用程序运行的机制。

我加载了json然后迭代对象集合并逐个添加到' Countries'采集。 但是,每次运行代码时,我都会得到一个" RangeError:超出最大调用堆栈大小"。

我已经搜索过,但似乎没有任何建议的解决方案适用于我。 我的猜测是我的insertCountry函数有问题......

无论如何,这是我的代码:

var mongoose = require('mongoose');
var countries = require('./seed/countries.json');


// mongodb
var Country = mongoose.Schema({
    name: String,
    code: String,
    extra: [Extra]
});

var Extra = mongoose.Schema({
    exampleField: Boolean,
    anotherField: Boolean
});


var mCountry = mongoose.model('Countries', Country);
var mExtra = mongoose.model('Extras', Extra);

// do connection
mongoose.connect('...');

var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error'));
db.once('open', function callback() {

});


// async function
var insertCountry = function(document, callback) {

    db.model('Countries').count({code: document.code}, function (err, count) {
        if (count < 1) {
            db.collection('Countries').insert(document, function (err, result) {
                if (!err) {
                    console.log('country ' + document.name + ' added');
                }
                else {
                    console.log('- [' + document.name + '] ' + err);
                }
            });
        }
        callback(null,document);
    });
};


// doing countries
var Country = mongoose.model('Countries');
var Extras = mongoose.model('Extras');


for(i = 0; i < countries.length; i++) 
{

    nCountry = new Country();
    nCountry.name = countries[i].name;
    nCountry.code = countries[i].code;
    nCountry.benefits = new Extras();
    nCountry.benefits.exampleField = false;
    nCountry.benefits.anotherField = false;

    insertCountry(nCountry, function (err, value) {
        console.log(value.name + ' added to collection (callback)');
    });
}

我一直在使用我发现的一些指南来构建它,所以这可能不是最佳代码。您可以分享任何您可以分享的最佳实践,标准,指南或教程!

1 个答案:

答案 0 :(得分:-1)

你的回调是在错误的地方。在从它自己的回调返回之前,它不会等待插入操作完成。改变你的代码:

var insertCountry = function(document, callback) {

    db.model('Countries').count({code: document.code}, function (err, count) {
        if (count < 1) {
            db.collection('Countries').insert(document, function (err, result) {
                if (!err) {
                    console.log('country ' + document.name + ' added');
                }
                else {
                    console.log('- [' + document.name + '] ' + err);
                }
                callback(null,document);
            });
        }
    });
};

这是你问题的一部分,但它并没有完全解决它。另一部分是循环,它也不等待包装功能在继续之前完成。您需要类似asyc.eachSeries之类的东西,以便在执行下一次迭代之前等待插入完成。这主要是为什么你超出了调用堆栈:

async.eachSeries(
    countries,
    function(current,callback) {
       // make your nCountry object
       insertCountry(nCountry,function(err,value) {
          // do something, then
          callback(err);
       }) 
    },
    function(err) {
       // called where done, err contains err where set
       console.log( "done" );
    }
);

阵列确实存在问题,如果超出调用堆栈限制,则必须相当大。您可能应该考虑使用事件流来处理,而不是将内存中的所有内容加载到数组中。

就个人而言,如果您只是尝试不为字段插入重复项并且可以使用MongoDB 2.6,那么我只需使用Bulk Operations API和#34;无序操作&#34;并允许重复键上的非致命故障。再加上批量操作是在批量生产中发送的。而不是一次一个,这比检查每个请求的存在要高效得多:

var Country = mongoose.Schema({
    name: String,
    code: { type: String, unique: true },  // define a unique index
    extra: [Extra]
});

var insertCountries = function(countries,callback) {
    var bulk = Country.collection.initializeUnorderedBulkOp();
    var counter = 0;

    async.eachSeries(
        countries,
        function(current,callback) {
            // same object construction
            bulk.insert(nCountry);
            counter++;

            // only send once every 1000
            if ( counter % 1000 == 0 ) {
                bulk.execute(function(err,result) {
                   // err should generally not be set
                   // but result would contain any duplicate errors
                   // along with other insert responses

                   // clear to result and callback
                   bulk = Country.collection.initializeUnorderedBulkOp();
                   callback();
                });
            } else {
                callback();
            }
        },
        function(err) {
            // send anything still queued
            if ( counter % 1000 != 0 )
                bulk.execute(function(err,result) {
                    // same as before but no need to reset
                    callback(err);
                });
        }
    );
};

mongoose.on("open",function(err,conn) {
    insertCountries(countries,function(err) {
        console.log("done");
    });
});

请记住,与直接在mongoose模型上实现的方法不同,本机驱动程序方法要求在调用之前实际建立连接。猫鼬&#34;队列&#34;这些都适合你,但你需要一些东西来确保连接实际上是开放的。 &#34; open&#34;的例子事件在这里使用。

同时查看event stream。如果你正在构建一个足够大的数组,因为缺少回调执行而导致问题,那么你可能不应该将它全部加载到内存中。如上所示,流处理结合上述方法的流处理应提供有效的加载。