2017-03-21 119 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