节点js中的同步for循环
Synchronous for loop in node js
假设我有以下 for 循环
for(var i = 0; i < array.length; i++){
Model.findOne({ _id = array[i].id}, function(err, found){
//Some stuff
});
}
如何使这段代码起作用?每次我 运行 它都会得到 array[i] = undefined
因为 mongo-db 查询是异步的,并且在第一个查询完成时循环已经迭代了 5 次。我该如何着手解决这个问题并等待查询完成才能继续下一次迭代?
完成您想要的事情的最简单方法之一是使用承诺。您可以使用库 q
来执行此操作:
var Q = require('q');
function fetchOne(id) {
var deferred = Q.defer();
Model.findOne({ _id = id}, function(err, found){
if(err) deferred.reject(err);
else deferred.resolve(found);
});
return deferred.promise;
}
function fetch(ids, action) {
if(ids.length === 0) return;
var id = ids.pop();
fetchOne(id).then(function(model) {
action(model);
fetch(ids, action);
});
}
fetch([1,2,3,4,5], function(model) { /* do something */ });
这不是最漂亮的实现,但我相信你明白了:)
这并没有具体回答您的问题,而是解决了您的问题。
我会使用 $in 查询并同时进行所有过滤。与 1:
相比,对数据库的 20 次调用非常慢
// grab your ids
var arrayIds = myArray.map(function(item) {
return item._id;
});
// find all of them
Model.find({_id: {$in: arrayIds}}, function(error, foundItems) {
if (error) {
// error handle
}
// set up a map of the found ids
var foundItemsMap = {};
foundItems.forEach(function(item) {
foundItemsMap[item._id] = true;
});
// pull out your items that haven't been created yet
var newItems = [];
for (var i = 0; i < myArray.length; i++) {
var arrayItem = myArray[i];
if ( foundItemsMap[arrayItem._id] ) {
// this array item exists in the map of foundIds
// so the item already exists in the database
}
else {
// it doesn't exist, push it into the new array
newItems.push(arrayItem);
}
}
// now you have `newItems`, an array of objects that aren't in the database
});
不确定这是否正确,它可能有点贵,但我是这样做的。
我认为诀窍是提取所有数据,然后寻找 ID 匹配项。
Model.find(function(err, data) {
if (err) //handle it
for (var i=0; i<array.length; i++) {
for (var j=0; ij<data.length; j++) {
if(data[j].id == array[i].id) {
// do something
}
}
}
}
假设我有以下 for 循环
for(var i = 0; i < array.length; i++){
Model.findOne({ _id = array[i].id}, function(err, found){
//Some stuff
});
}
如何使这段代码起作用?每次我 运行 它都会得到 array[i] = undefined
因为 mongo-db 查询是异步的,并且在第一个查询完成时循环已经迭代了 5 次。我该如何着手解决这个问题并等待查询完成才能继续下一次迭代?
完成您想要的事情的最简单方法之一是使用承诺。您可以使用库 q
来执行此操作:
var Q = require('q');
function fetchOne(id) {
var deferred = Q.defer();
Model.findOne({ _id = id}, function(err, found){
if(err) deferred.reject(err);
else deferred.resolve(found);
});
return deferred.promise;
}
function fetch(ids, action) {
if(ids.length === 0) return;
var id = ids.pop();
fetchOne(id).then(function(model) {
action(model);
fetch(ids, action);
});
}
fetch([1,2,3,4,5], function(model) { /* do something */ });
这不是最漂亮的实现,但我相信你明白了:)
这并没有具体回答您的问题,而是解决了您的问题。
我会使用 $in 查询并同时进行所有过滤。与 1:
相比,对数据库的 20 次调用非常慢// grab your ids
var arrayIds = myArray.map(function(item) {
return item._id;
});
// find all of them
Model.find({_id: {$in: arrayIds}}, function(error, foundItems) {
if (error) {
// error handle
}
// set up a map of the found ids
var foundItemsMap = {};
foundItems.forEach(function(item) {
foundItemsMap[item._id] = true;
});
// pull out your items that haven't been created yet
var newItems = [];
for (var i = 0; i < myArray.length; i++) {
var arrayItem = myArray[i];
if ( foundItemsMap[arrayItem._id] ) {
// this array item exists in the map of foundIds
// so the item already exists in the database
}
else {
// it doesn't exist, push it into the new array
newItems.push(arrayItem);
}
}
// now you have `newItems`, an array of objects that aren't in the database
});
不确定这是否正确,它可能有点贵,但我是这样做的。 我认为诀窍是提取所有数据,然后寻找 ID 匹配项。
Model.find(function(err, data) {
if (err) //handle it
for (var i=0; i<array.length; i++) {
for (var j=0; ij<data.length; j++) {
if(data[j].id == array[i].id) {
// do something
}
}
}
}