[英]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.