我实际上是使用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)');
});
}
我一直在使用我发现的一些指南来构建它,所以这可能不是最佳代码。您可以分享任何您可以分享的最佳实践,标准,指南或教程!
答案 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。如果你正在构建一个足够大的数组,因为缺少回调执行而导致问题,那么你可能不应该将它全部加载到内存中。如上所示,流处理结合上述方法的流处理应提供有效的加载。