2017-03-21 16 views
0

私はNode.jsでシステムを開発しています。状況は次のとおりです。私にIdリストを返すプロミスがあり、そのプロミス(その時)の代わりに、最初のメソッドで返された項目のそれぞれについてクエリを実行する必要があります。returnそれぞれのために約束する

これを行うにはどうすればよいでしょうか?

checkLastPosition(list) { 
    let returnList = new Array(); 
    var actualDate = new Date(); 
    list.forEach(function (item) { 
     return new Promise((resolve, reject) => { 
      pool.getConnection(function (err, connection) { 

       if (err) 
        reject(err); 

       let sql = ' select * from posicao loc'; 
       sql += ' where veiculoid = ?'; 
       sql += ' and loc.dataHora = (select max(dataHora) from posicao where veiculoId = loc.veiculoId)'; 
       sql += ' order by loc.veiculoid, datahora desc'; 

       connection.query(sql, item.veiculoid, function (err, rows) { 

        connection.release(); 

        if (err) 
         reject(err); 

        resolve(rows[0]); 
       }); 
      }); 
     }).then(result => { 


      if (!result) { 
       returnList.push(item.veiculoId); 
      } else { 
       if (new Date(result.dataHora.toLocaleString()) <= actualDate.setMinutes(actualDate.getMinutes() - 10)) { 
        returnList.push(item.veiculoId); 
       } 
      } 
     }); 

    }, this); 
} 
+0

'forEach'の代わりに' map'を使用して、Promiseの結果の配列に 'Promise.all'を適用します。 – Bergi

+0

どうすればいいですか? –

答えて

1

まず、list.map()list.forEach()呼び出しに変換:

私のコードは次のようです。 map()を使用すると、一連の約束を構築できます。すべての約束は、クエリの結果を含んでいます。

約束事のリストをqueriesという変数に保存します。次に、Promise.all()を使用して、queriesのすべての約束が解決されるか、少なくとも1つが却下された場合に、解決済み/拒絶約束を生成します。

thenの呼び出しをPromise.all()に添付すると、resolveコールバックにはクエリの結果が格納された配列が渡されます。ここでは結果をループしてreturnList配列を作成して返すことができます。

returnListを約束してthen()によってラップされます、この約束はメソッドの呼び出し元に返されます。

checkLastPosition(list) { 
    let queries = list.map(function (item) { 
     return new Promise((resolve, reject) => { 
      pool.getConnection(function (err, connection) { 
       if (err) reject(err); 

       let sql = ' select * from posicao loc'; 
       sql += ' where veiculoid = ?'; 
       sql += ' and loc.dataHora = (select max(dataHora) from posicao where veiculoId = loc.veiculoId)'; 
       sql += ' order by loc.veiculoid, datahora desc'; 

       connection.query(sql, item.veiculoid, function (err, rows) { 
        connection.release(); 
        if (err) reject(err); 

        resolve(rows[0]); 
       }); 
      }); 
     }); 
    }, this); 

    return Promise.all(queries).then(results => { 
     let returnList = new Array(); 
     var actualDate = new Date(); 
     results.forEach(result => { 
      if (!result) { 
       returnList.push(item.veiculoId); 
      } else { 
       if (new Date(result.dataHora.toLocaleString()) <= actualDate.setMinutes(actualDate.getMinutes() - 10)) { 
        returnList.push(item.veiculoId); 
       } 
      } 
     }); 
     return returnList; 
    }); 
} 
+0

さて、returnListをどうやって返すのですか? –

+0

'returnList'を返す方法を示す答えを更新しました。 – Andrea

+0

完璧に働いた、ありがとう! –

0

私はあなたがmysqljsを使用していると仮定します。

1つのSQLクエリを実行するいくつかの約束事を作成するのではなく、ただ1つの約束事を作成して、SQLクエリがinの入力リスト全体をチェックするようにします。この方法では、データベースを1回だけ照会します。

私はこの表現であなたが実際にその変数を変更するので、あなたはまた、 actualDateの問題を持っていると思う

actualDate.setMinutes(actualDate.getMinutes() - 10) 

式が評価されるたびに、それはそれから10分を差し引くので、あなたは比較に終わります-10、-20、-30、...分です。ここで

いくつかある - テストしていない - アイデアを示すコード:私はIDの動的なリストと同じように、あなたは合格する必要があり、離れたクエリで?を使用してからステップ

checkLastPosition(list) { 
    var actualDate = new Date(); 
    // Be careful: setMinutes will mutate the variable -- don't repeat it: 
    actualDate.setMinutes(actualDate.getMinutes() - 10); 

    return new Promise((resolve, reject) => { 
     pool.getConnection(function(err, connection) { 
      if(err) 
       reject(err); 
      let sql = ' select * from posicao loc'; 
       sql += ' where veiculoid in (' + // use IN operator and inject escaped list of ID values 
          list.map(item => connection.escape(item.veiculoid)).join(',') + ')'; 
       sql += ' and loc.dataHora = (select max(dataHora) from posicao where veiculoId = loc.veiculoId)'; 
       sql += ' order by loc.veiculoid, datahora desc'; 
      connection.query(sql, function(err, rows) { // no more bound variables 
       connection.release(); 
       if(err) 
        reject(err); 
       resolve(rows); // all rows 
      }); 
     }); 
    }).then(result => { 
     // Identify which records should be excluded, and make a Set of them, for faster lookup 
     const toExclude = 
      new Set(result.filter(record => new Date(record.dataHora.toLocaleString()) > actualDate) 
          .map(record => record.veiculoid) 
        ); 
     // Take the original list of items, and exclude the ones from it according to that Set: 
     return list.map(item => item.veiculoid).filter(veiculoid => !toExclude.has(veiculoid)); 
    }); 
} 

注意これらの数は同じです。 APIがちょうどconnection.escape()を内部的に使用していることをドキュメントで読んだので、私はちょうど?の代わりにその関数を使用しました。

+0

私はselectが遅すぎるので "in"を使わないことにしましたが、提案のおかげで –

+0

'in'は' = 'で* n *個のクエリを実行する時間よりも遅くならないようにしてください。それが実際にそれより遅い場合、それは正常ではないので、索引を見る必要があるかもしれません。 – trincot

関連する問題