节点行为
Nodejs behaviour
我一直在做nodeJS+MongoDB,用了几个月的Express和Mongoose框架,想请教各位,遇到下面这样的情况到底是怎么回事:
Model1.find({}, function (err, elems) {
if (err) {
console.log('ERROR');
} else {
elems.forEach(function (el) {
Model2.find({[QUERY RELATED WITH FIELDS IN 'el']}, function (err, elems2) {
if (err) {
console.log('ERROR');
} else {
//DO STAFF.
}
});
});
}
});
我最好的猜测是有一个主线程在 elems 上循环,然后不同的线程参与 Model2 上的每个查询,但我不太确定。
对吗?而且,这是一个好的解决方案吗?如果不是,在这种情况下,您将如何编码,您需要从 Model1 获取的每个元素中的信息以从 Model2 获取元素,并执行您正在寻找的实际功能?
我知道我可以详细说明一个更复杂的查询,在那里我可以获得 elems 中每个 'el' 的所有元素,但我宁愿不这样做,因为那样的话我会担心内存开销。
此外,我一直在考虑更改数据模型,但我已经仔细研究过了,我相信这是经过深思熟虑的,但我认为这不是我的应用程序的最佳解决方案。
谢谢!
NodeJS 是一个单线程环境,它异步工作以阻止函数调用,例如您的情况下的网络请求。所以只有一个线程,你的查询结果将被异步调用,这样就不会因为密集的网络操作而阻塞任何东西。
在您的场景中,如果第一个查询 returns 相当多的记录,例如 100000 千条,您可能会在循环中耗尽 mongo 服务器,因为您将查询与结果一样多的服务器立即查询。这是因为节点在异步工作时不会停止接收每个查询的结果。
因此通常手动限制对网络操作的请求是一个很好的做法。在异步环境中工作时,这不是微不足道的。一种方法是使用递归函数调用。基本上,您将任务分成几组,然后分批完成每组,一旦完成了一批,您就可以开始下一组。
这里有一个简单的例子说明如何做,我使用了 promises 而不是回调函数,Q 是一个对处理 promises 非常有用的 promise 库:
var rows = [...]; // array of many
function handleRecursively(startIndex, batchSize){
var promises = [];
for(i = 0; i < batchSize && i + batchSize < rows.length; i++){
var theRow = rows[startIndex + i];
promises.push(doAsynchronousJobWithTheRow(theRow));
}
//you wait until you handle all tasks in this iteration
Q.all(promises).then(function(){
startIndex += batchSize;
if(startIndex < rows.length){ // if there is still task to do continue with next batch
handleRecursively(startIndex, batchSize); }
})
}
handleRecursively(0, 1000);
这是最佳解决方案:
Model1.find({}, function (err, elems) {
if (err) {
console.log('ERROR');
} else {
loopAllElements(0,elems);
}
});
function loopAllElements(startIndex,elems){
if (startIndex==elems.length) {
return "success";
}else{
Model2.find({[QUERY RELATED WITH FIELDS IN elems[startIndex] ]}, function (err, elems2) {
if (err) {
console.log('ERROR');
return "error";
} else {
//DO STAFF.
loopAllElements(startIndex+1, elems);
}
});
}
}
我一直在做nodeJS+MongoDB,用了几个月的Express和Mongoose框架,想请教各位,遇到下面这样的情况到底是怎么回事:
Model1.find({}, function (err, elems) {
if (err) {
console.log('ERROR');
} else {
elems.forEach(function (el) {
Model2.find({[QUERY RELATED WITH FIELDS IN 'el']}, function (err, elems2) {
if (err) {
console.log('ERROR');
} else {
//DO STAFF.
}
});
});
}
});
我最好的猜测是有一个主线程在 elems 上循环,然后不同的线程参与 Model2 上的每个查询,但我不太确定。
对吗?而且,这是一个好的解决方案吗?如果不是,在这种情况下,您将如何编码,您需要从 Model1 获取的每个元素中的信息以从 Model2 获取元素,并执行您正在寻找的实际功能?
我知道我可以详细说明一个更复杂的查询,在那里我可以获得 elems 中每个 'el' 的所有元素,但我宁愿不这样做,因为那样的话我会担心内存开销。
此外,我一直在考虑更改数据模型,但我已经仔细研究过了,我相信这是经过深思熟虑的,但我认为这不是我的应用程序的最佳解决方案。
谢谢!
NodeJS 是一个单线程环境,它异步工作以阻止函数调用,例如您的情况下的网络请求。所以只有一个线程,你的查询结果将被异步调用,这样就不会因为密集的网络操作而阻塞任何东西。
在您的场景中,如果第一个查询 returns 相当多的记录,例如 100000 千条,您可能会在循环中耗尽 mongo 服务器,因为您将查询与结果一样多的服务器立即查询。这是因为节点在异步工作时不会停止接收每个查询的结果。
因此通常手动限制对网络操作的请求是一个很好的做法。在异步环境中工作时,这不是微不足道的。一种方法是使用递归函数调用。基本上,您将任务分成几组,然后分批完成每组,一旦完成了一批,您就可以开始下一组。
这里有一个简单的例子说明如何做,我使用了 promises 而不是回调函数,Q 是一个对处理 promises 非常有用的 promise 库:
var rows = [...]; // array of many
function handleRecursively(startIndex, batchSize){
var promises = [];
for(i = 0; i < batchSize && i + batchSize < rows.length; i++){
var theRow = rows[startIndex + i];
promises.push(doAsynchronousJobWithTheRow(theRow));
}
//you wait until you handle all tasks in this iteration
Q.all(promises).then(function(){
startIndex += batchSize;
if(startIndex < rows.length){ // if there is still task to do continue with next batch
handleRecursively(startIndex, batchSize); }
})
}
handleRecursively(0, 1000);
这是最佳解决方案:
Model1.find({}, function (err, elems) {
if (err) {
console.log('ERROR');
} else {
loopAllElements(0,elems);
}
});
function loopAllElements(startIndex,elems){
if (startIndex==elems.length) {
return "success";
}else{
Model2.find({[QUERY RELATED WITH FIELDS IN elems[startIndex] ]}, function (err, elems2) {
if (err) {
console.log('ERROR');
return "error";
} else {
//DO STAFF.
loopAllElements(startIndex+1, elems);
}
});
}
}