2017-03-21 121 views
0

我正在開發Node.js中的系統,情況是這樣的:我有一個承諾,返回我一個Id列表,並在該承諾(然後)的回報我調用另一種方法需要爲第一個方法中返回的每個項目執行查詢。返回承諾與每個

這樣做的最好方法是什麼?

我的代碼是這樣的:

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

使用'map'而不是'forEach',並將'Promise.all'應用於結果數組中。 – Bergi

+0

我該怎麼做? –

回答

1

首先,轉換list.forEach()調用到list.map()。使用map()您可以構建一組承諾。每個承諾都包含查詢的結果。

將該承諾列表保存在名爲queries的變量中。然後使用Promise.all(),當queries中的所有承諾都已解決或至少有一個承諾被拒絕時,將生成已解決/已拒絕的承諾。

這樣做,您可以附加一個then調用Promise.all(),解析回調將收到一個包含查詢結果的數組。在這裏你可以遍歷結果,構建你的returnList數組並返回它。

returnListthen()的承諾來包裝,此承諾將返回到方法的調用者:

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

而不是創建幾個承諾,每個執行一個SQL查詢,我會創建一個承諾,並讓SQL查詢在整個輸入列表中執行in檢查。這樣你只會查詢一次數據庫。

我想你也有一個問題與actualDate,因爲在此表達你實際上修改變量:

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

每一次表達式,它從它減去10分鐘路程,所以你最終比較與-10,-20,-30,...分鐘。

下面是一些 - 未經檢驗的 - 說明這個想法代碼:

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)); 
    }); 
} 

注意,我在查詢中使用?,與ID的動態列表走開,你就需要通過相同數量的這些。正如我在文檔中所讀到的,API僅在內部使用connection.escape(),我只是使用該函數而不是?

+0

我決定不使用「in」,因爲select太慢,但是感謝 –

+0

'in'的建議不應該比用'='做* n *個別查詢的時間慢。如果真的比這慢,那麼你可能需要看索引,因爲這是不正常的。 – trincot