我在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分配给每一行。 该代码有效(日志给出了正确的输出),但在第一个承诺被发回后 之后执行。
我如何做出第一个承诺,直到将AdditionalData分配给对象?
非常感谢您!
最诚挚的问候
答案 0 :(得分:1)
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做错了。
答案 1 :(得分:0)
以下,我对您的代码进行了一些更改,以使我们可以观察到发生的行为(查看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));
答案 2 :(得分:0)
好吧,我在阅读以下内容后找到了解决方法:
文章说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!');
});
答案 3 :(得分:0)
使用以下代码获取类别和子类别。如何按类别获取子类别?
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;
}