2017-05-30 5 views
0

私はmongodbとbigqueryでnodejsを使用しています。nodejsループの次のインスタンスを実行するまで待機する方法

だから、bigqueryのようにコマンドごとに10kの挿入しかできないようです。

私はメインクエリをカウントし、10kからいくつのページにループしました。

私はカウントクエリで50万ペー​​ジを取得します。つまり、50ページまたは500ループです。

ループの次のページを実行するまでループ待機を行う方法はありますか?

コード:

var limit = 9999; 

mongo_client.connect(mongo_url, function(err, db) { 
    var query = {'_id.date_visited':{'$gte':'2016-01-01','$lt':'2016-02-01'}}; 

    db.collection('my_table').count(query,function(err, count){ 
     var pages = Math.ceil(count/limit); 

     console.log("count: "+count); 
     console.log("pages: "+pages); 

     for(var page=0;page<pages;page++){ 
      var skip = page * limit; 

      console.log("page: "+page); 
      console.log("skip: "+skip); 

      //HOW TO MAKE THIS loop wait till running next page of the loop 
      db.collection('my_table').find(query).sort({'_id.date_visited':1,'_id.hour_visited':1}).limit(limit).limit(skip).toArray(function(err, db_results) { 
       var documents = []; 
       async.each(db_results, function (db_resultsx, cb) { 
        documents.push(db_resultsx); 

        if(documents.length == db_results.length) { 
         //console.log(documents); 
         bigqueryClient 
          .dataset(dataset) 
          .table('my_table') 
          .insert(documents) 
          .then((insertErrors) => { 
          console.log('Inserted'); 
          //documents.forEach((row) => console.log(row)); 
          console.error(insertErrors); 
          if (insertErrors && insertErrors.length > 0) { 
           console.log('Insert errors:'); 
           insertErrors.forEach((err) => console.error(err)); 
          } 
          }) 
          .catch((err) => { 
          console.error('ERROR:'); 
          console.log(err); 
         }); 
        } 
       }); 
      }); 
     } 
    }); 
}); 
+0

あなたは既に['async.each'](http://caolan.github.io/async/docs.html#each)を使用しています。この行を見る 'async.each(db_results、function(db_resultsx、cb){' 'cb'はループの次の繰り返しを通知するときに実行されることを意図しています。ステートメントを別の非同期メソッドの前に置く必要があります。そのため、非同期メソッド(bigQuery)と 'else'条件の両方で' callback 'を呼び出す必要があります。 –

答えて

1

私はおそらくループの次の反復が発生したときに、あなたが決めることができ、かつasync.eachSeries以来、一度に1つの操作を実行しますasync.eachSeriesとのforループを置き換えます、あなたは、同じエラーに実行されません

EDIT:

コードを読んだ後、私は薄いですk async.timesSeries(私のコメントからの訂正、async.timesSeriesが正しいオプションです)より良い賭けです。ここでは例です:上記のコードは置き換えられます

async.timesSeries(pages, function(page, next) 
{ 
    var skip = page * limit; 
    // ... the rest of your code here 

    // when you want the next iteration to start, simply call: 
    next(); 
    /* 
    which will tell async that the current iteration is complete, 
    and it can do the next one. You can pass 2 parameters to next, 
    the first parameter is an error, and if error is not null it will 
    immediately call the function below, and the second parameter is an 
    item you can pass that will be added to an object which will be sent 
    as the second parameter in the function below 
    */ 
}, 
function(err, coll) 
{ 
    /* 
    this function will get called if there's an error 
    or when all iterations are completed 
    */ 
}); 

あなたのforループ

+0

私はeachSeriesにページ数を送り、何回もループしたり繰り返したりする必要がありますか? – Boy

+1

ここで意図を少し誤って読んでしまい、コードを適切に調べた後に['async.times' ](https://caolan.github.io/async/docs.html#times)はコールバックを許可するので、必要に応じてループの次の部分だけを実行できるので、より便利です'n'回だけ実行されます。 – Chifilly

+0

は.timesの内部でデフォルトとして実行されます。 l内部のコードは次のループに行くまで終了しますか?または何か他のことをする必要がありますか?私はノードで新しいです。 – Boy

2

私はforループのように再帰呼び出しを使用して、この場合、あなたができるループのための良い解決策ではないだろうと思う:

function performQuery(queryIndex) { 
    if(queryIndex >= limit) return; 

    db.exec('query', function(err, db_result) { 
     // your code 
     performQuery(queryIndex+1); 
    }) 
} 
performQuery(0); 
+0

私はこの考えが好きですが、コード内ではbigqueryにデータをアップロードするので、次のperformQueryを実行するまで待つか、bigqueryコールバックでperformQueryを実行する必要がありますか? – Boy

+1

bigqueryの最後まで待っていて、bigqueryコールバックでperformQueryを実行したい場合 –

0

あなたは再帰的な約束を使用したくない、とあなたは事前にアイテムの数を知っていることを考えると、あなたはこのようにそれを行うことができた場合:

// Create a "skip" array (there is certainly a nicer way to do it, with a modulo) 
var skips = []; 
for(var page=0;page<pages;page++){ 
    skips.push(page * limit); 
} 

// Put your mongoDB read and write code in a function 
// (that takes skip in entry and returns an array of documents) 
var myMongoDBFunc = function (skip) { 
    var documents = []; 

    db.collection('my_table') 
     .find(query) 
     .limit(limit) 
     .limit(skip) 
     .toArray(function(err, db_results) { 
      ... 
     }); 
    ... 
    return documents; 
} 

// And call it with async.concatSeries that will concatenate the results (documents) 
async.concatSeries(skips, myMongoDbFunc, function(err, documents) { 
    // Will be called at the end 
}); 

すべてのクエリを並列に最適化して実行する場合は、concatSeriesconcatに置き換えてください(ただし、順序は保証されません)。

そして、あなたは多分あなたはasync.seriesまたはasync.parallel(私は特にasyncを知らない、自分で確認してください)を使用することができ、返されたドキュメント(どうやらあなただけの何かを書きたい)気にしないのであれば。

関連する問題