Nodejs Loop和Mongodb Save导致Mongodb MAx连接

时间:2017-06-18 08:17:08

标签: javascript node.js mongodb

想象以下脚本

var startPage = 1
var endPage = 40



 for (y = startPage; y < endPage ; y++) { 

 var y = Number(y)
 var search = getresult.from.Myapiforexample

search.run().then(function (data) {

   //////////////////

    /// This will generate 35 results//

         var myresult = data.results



   for (i = 0; i < myresult.length; i++) { 
            data.results[i].getDetails().then(function (details) {

              savetodb(details)

            }, function (err) {
                console.error(err);
            });
    }   

}, function (err) {
    console.error(err);
});

}




function savetodb(json) {

    var getsession = function(db, callback) {
          var collection = db.collection('thebase');

              collection.insert(data, function (err, docs) {
              callback(docs);
                 db.close();
              });
      };
       MongoClient.connect(url, function(err, db) {
          getsession(db, function(docs) {


              console.log("Recording ok")


          });
      });

}

第一个循环(带y)运行40时间每个生成35个结果。 所以我将有40 X 35记录保存到Mongo数据库 这将达到我的mongodb Maxx连接。 所以我要做的是:

创建一个空数组

var myarray = []  // ok 

push each "details" to myarray

myarray.push(details)

但我的问题是因为nodeJS是异步的,我需要等待y循环结束才能保存到db

那么在将myarray发送到保存功能之前,我怎么能等待Y循环完成。 没有实现等待时间..?

我尝试使用回调,承诺没有任何成功..

3 个答案:

答案 0 :(得分:0)

你可以使用Promise.all。首先将promises存储在一个数组中:

var promises=[];
//in the loop
promises.push(data.results[i].getDetails());

所以现在你可以等待所有这些并保存它们:

Promise.all(promises).then(savetodb);//passes all results to savetodb in an array

您可能希望启用savetodb将数组作为参数,但这取决于您...

但是,不是为每个操作打开新连接,而只需保留一个:

var db=new Promise(function(res,rej){//in global scope
 MongoClient.connect(url, function(err, db) {
   if(err) return rej(err);
   res(db);
 });
});

现在,您可以随处访问此连接:

db.then(function(db){
  //db is our database
});

你可以像这样实现错误处理:

db.catch(function(err){
  console.log("fatal db error. shutting down. "+err);
  process.exit();
});

答案 1 :(得分:0)

相当复杂的东西。我希望这有效,因为我无法测试它。我基本上大量使用嵌套的Promise.all,在我看来我认为是必要的:

var startPage = 1;
var endPage = 40;

var searchPromises = [];

// make the searches
for (var y = startPage; y < endPage; y++) {
  searchPromises.push(getresult.from.Myapiforexample.run());
}

// create a database connection
new Promise(function (resolve, reject){
  MongoClient.connect(url, function(error, database) {
    if (error) {
      return reject(error);
    }
    resolve(database);
  });
}).then(function (db) {
  var collection = db.collection('thebase');
  Promise.all(searchPromises).then(function (dataArray) {
    // dataArray contains an array of an array of search results
    var results = dataArray.map(function (data) {
      // data contains an array of search results
      return data.results.map(function (result) {
        return result.getDetails();
      });
    });
    // results is an array of arrays, flatten it:
    var resultPromises = [].concat.apply([], results);
    return Promise.all(resultPromises);
  }).then(function (results) {
    var insertPromises = results.map(function (result) {
      return new Promise(function (resolve, reject) {
        collection.insert(result, function (error, docs) {
          if (error) {
            reject(error);
          }
          resolve(docs);
        });
      });
    });
    return Promise.all(insertPromises);
  }).then(function (docsArray) {
    // docsArray contains an array of the docs parameter of the callback in collection.insert
    console.log('All recordings OK.');
  }).catch(function (error) {
    console.log('Could not insert data into database', error);
  });
}).catch(function (error) {
  console.log('Could not connect to database', error);
});

这样,您不必创建40次35个数据库连接。

答案 2 :(得分:0)

由于以下事实,您会收到最大连接错误:

function savetodb(json) {

    var getsession = function(db, callback) {
        var collection = db.collection('thebase');

        collection.insert(data, function (err, docs) {
        callback(docs);
           db.close();
        });
    };
    MongoClient.connect(url, function(err, db) {
        getsession(db, function(docs) {

        console.log("Recording ok")


        });
    });
}

每次调用此getsession函数时,都会打开一个与mongodb的新连接。并且您大约getsession(endPage - startPage) * (data.results.length)次,这超过了您的mongodb实例接受的最大连接数。

你应该做的是:

您在程序开始时执行MongoClient.connect一次,将db存储在全局变量中,并且只有在您完成执行MongoClient.connect之后才能开始插入数据并且不要只要程序执行,就关闭db

这是做事的一种方式。

但是这种方式不会扩大生产规模。对于生产,您应该使用连接池。这意味着:

  1. 在程序开始时,您多次连接到mongodb并将每个db存储在一个数组中。
  2. 当您执行插入操作时,您会从数组中获得一个db
  3. 完成插入操作后,将db返回给阵列。
  4. 如果阵列中没有可用的db,则等待其中一个可用。
  5. 我猜mongodb有很多连接池实现,包括很多原生的实现。只需选一个。