首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Node.js mysql嵌套查询和异步/等待

Node.js mysql嵌套查询和异步/等待
EN

Stack Overflow用户
提问于 2018-07-24 01:29:04
回答 4查看 2.7K关注 0票数 1

我在Google或Stackoverflow上找不到这个问题的答案,也许你能帮我。我在mysql和express中使用Node.js。

因为Node.js是异步的,所以我使用async/await。

此应用程序应返回一个嵌套对象,如下所示:

    [{
      "name":"Name1",
      "additionalData": [
       {
        "data1": "data", 
        "data2": "data"
       }
      ]
    },
      {"name":"Name2",
      "additionalData": [
       {
        "data1": "data", 
        "data2": "data"
       }
      ]
    }]

代码如下(简化):

var express = require('express');
var mysql = require('mysql');
var app = express();

var con = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "password",
    database: "database"
  });

con.connect(function(err) {
    if (err) throw err;
    console.log("Connected!");
  });

async function getData() { 
      var sql = 'Select name from users' 

      let promise = new Promise((resolve, reject) => {

        con.query(sql, async (err, resultSet) => { 
          if (err) reject(err); 

          let promisesub = new Promise((resolvesub, rejectsub) => {
            con.query('Select data from othertable', (err, rs) => { 
              resolvesub(rs)       
            }) 
          })

          resultSet.forEach(async (row) => { 
            row.additionalData = await promisesub;
            console.log(row)
           }); 

          resolve(resultSet);
        }) 

      })

      let result = await promise;

      return result;
} 

app.get('/', function (req, res) { 

  getData().then(function(rows) { 
    res.send(rows) 
  }).catch(function(err) { 
    console.log(err) 
  }) 
}); 

app.listen(3000, function () {
  console.log('Backend listening on port 3000!');
});

因此,如果我调用http://localhost:3000/,我只会得到get名称(没有第二个查询中的附加数据):

[{"name":"Name1"},
{"name":"Name2"}]

问题是只返回第一个promise的结果。forEach循环中的代码应该将additionalData分配给每一行。代码正在工作(日志给出了正确的输出),但是在发送回第一个promise之后执行了

如何让第一个promise等待,直到将additionalData分配给对象?

非常感谢!

诚挚的问候

EN

回答 4

Stack Overflow用户

发布于 2018-07-24 06:03:45

Select data from othertable

从该表中获取所有数据,而不考虑关联的“名称”是什么。

此外,您正在做大量在SQL中“微不足道”的工作。这将为您完成内部循环的所有工作:

SELECT  n.name, a.data1, a.data2
    FROM  Names AS n
    JOIN  AdditionalData AS a  ON a.name = n.name 

(注意:如果看不到SHOW CREATE TABLE,我就不能确定我猜到了数据的模式。)

一般来说,如果你想“嵌套查询”,那么你做的SQL就是“错误的”。

票数 3
EN

Stack Overflow用户

发布于 2018-07-24 03:25:38

下面我对你的代码做了一些修改,我们可以看到行为发生的方式(看看http://jsfiddle.net,然后把下面的代码放在下面看看,或者其他游戏场地)

            var con = {
        connect : function (fnc) { fnc()},
        query : function (sql, pr) {
            if (sql === 'Select name from users') {
              setTimeout(
                  () => pr(null,[{id:1},{id:2}]), 2000
              )
            } else {
              setTimeout(
                  () => pr(null,[{id:3},{id:4}]), 2000
              )
            }
        }
      }

      con.connect(function(err) {
          if (err) throw err;
          console.log("Connected!");
        });

      async function getData() { 
            var sql = 'Select name from users' 

            let promise = new Promise((resolve, reject) => {

              con.query(sql, async (err, resultSet) => { 
                if (err) reject(err); 

                let promisesub = new Promise((resolvesub, rejectsub) => {
                  con.query('Select data from othertable', (err, rs) => { 
                    resolvesub(rs)       
                  }) 
                })

                resultSet.forEach(async (row) => {
                  console.log('for each');
                  row.additionalData = await promisesub;
                  console.log(' step 1', row);
                 }); 

                resolve(resultSet);
              }) 

            })

            let result = await promise;

            return result;
      } 

      getData().then(function(rows) { 
          console.log('step 2 ',  rows); 
        }).catch(function(err) { 
          console.log(err) 
        });

它的返回值恰好是这样的

Connected!
(index):61 for each
(index):77 step 2  (2) [{…}, {…}]
(index):63  step 1 {id: 1, additionalData: Array(2)}
(index):63  step 1 {id: 2, additionalData: Array(2)}

我注意到的第一件事是,问题并不在于你正在使用的库。它位于您创建的第二个异步环境中,该环境包含进程,但仅在函数forEach内。因此,它将通过forEach,尽管forEach的序列将是正确的…对于此场景,请使用其他辅助promise:

        let auxProm = new Promise(resolve => {
            resultSet.forEach(async (row) => {
              console.log('for each');
            row.additionalData = await promisesub;
              console.log(' step 1', row);
            }); 
          resolve(resultSet)
        })
        auxProm.then(auxResultSet => resolve(auxResultSet));
票数 0
EN

Stack Overflow用户

发布于 2018-07-24 21:30:39

好的,我在读完这篇文章后找到了解决方案:

Link

文章说forEach函数不会等待回调完成,所以我实现了自己的asyncForEach函数。

以下是工作的代码:

var express = require('express');
var mysql = require('mysql');
var app = express();

var con = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "admin",
    database: "db"
  });

  con.connect(function(err) {
    if (err) throw err;
    console.log("Connected!");
  });


async function getData() { 
      var sql = 'Select name from user' 

      let promise = new Promise((resolve, reject) => {

        con.query(sql, async (err, resultSet) => { 
          if (err) reject(err); 

          // asyncForEach
            async function asyncForEach(array, callback) {
              for (let index = 0; index < array.length; index++) {
                await callback(array[index], index, array)
              }
            } 

            //Subdata
            let promisesub = new Promise((resolvesub, rejectsub) => {
              con.query('Select data from othertable', (err, rs) => { 
                  resolvesub(rs)       
          }) 
        })

          const start = async () => {
              await asyncForEach(resultSet, async (row) => {
                row.additionalData = await promisesub;
              })
          resolve(resultSet)
          //console.log('ready')
          };

          start()
        }) 
      })

      let result = await promise;

      return result;
} 

app.get('/', function (req, res) {

    getData().then(function(rows) { 
        //console.log('step 3 ',  rows); 
        res.send(JSON.stringify(rows))
      }).catch(function(err) { 
        console.log(err) 
      });
});

app.listen(3000, function () {
    console.log('Example app listening on port 3000!');
  });  
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51484301

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档