簡體   English   中英

Node.js mysql - 嵌套查詢和異步/等待

[英]Node.js mysql - Nested queries and async/await

我在 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/我只獲取名稱(沒有來自第二個查詢的附加數據):

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

問題是只返回第一個承諾的結果。 forEach 循環中的代碼應該將 additionalData 分配給每一行。 代碼正在工作(日志給出了正確的輸出),但第一個承諾被發回后執行。

我怎樣才能讓第一個承諾等到附加數據分配給對象?

非常感謝!

此致

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 是“錯誤的”。

下面我以某種方式對您的代碼進行了一些更改,我們可以看到正在發生的行為(查看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 的序列是正確的...對於這種情況,請使用其他輔助承諾:

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

好的,我在閱讀本文后找到了解決方案:

關聯

文章說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!');
  });  

使用以下代碼獲取類別和子類別。 如何按類別獲取子類別?

async function getData() {
var sql1 = 'Select name from category'
let promise = new Promise((resolve, reject) => {

    sql.query(sql1, 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
        

        const start = async () => {
            await asyncForEach(resultSet, async (row) => {
            let promisesub = new Promise((resolvesub, rejectsub) => {
              sql.query(`Select * from subcategory cat_id=${row.id}`, (err, rs) => {
                  resolvesub(rs)
              })
            })
                row.subcategory = await promisesub;
            })
            resolve(resultSet)
            //console.log('ready')
        };

        start()
    })
})

let result = await promise;
return result;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM