【问题标题】:Nested queries in MYSQL and nodejs Async IssueMYSQL 和 nodejs 异步问题中的嵌套查询
【发布时间】:2019-02-08 04:25:50
【问题描述】:

我想为另一个查询的每一行执行一个 sql 查询,所以我写了一个类似

的函数
export function getLocations(req, res) {
let appData = [];
const database = new Database();
database.query('select * from districts')
    .then(rows => {
        rows.forEach(row => {
            const new_database = new Database();
            new_database.query(`SELECT locations.id,locations.name
            FROM locations 
            .....
            WHERE locations.district=?`, row.id)
                .then(sub_rows => {
                    let district = row;
                    district["locations"] = sub_rows;
                    appData.push(district);
                    new_database.close();
                }, err => {
                    return new_database.close().then(() => { throw err; })
                })
                .catch(err => {
                    console.log(err);
                    res.status(500).json("Database Error");
                })
    }, err => {
        return database.close().then(() => { throw err; })
    }).then(result => {
        //final result
        res.status(200).json(appData);
        database.close()
    })
    .catch(err => {
        console.log(err);
        res.status(500).json("Database Error");
    })
}

我的数据库类是

const mysql = require('mysql');

class Database {
constructor() {
    this.connection = mysql.createConnection({
        host: process.env.DB_HOST,
        user: process.env.DB_USERNAME,
        password: process.env.DB_PASSWORD,
        database: process.env.DB_NAME,
        port: 3306,
        debug: false,
        multipleStatements: false
    });
}
query(sql, args) {
    return new Promise((resolve, reject) => {
        this.connection.query(sql, args, (err, rows) => {
            if (err)
                return reject(err);
            resolve(rows);
        });
    });
}
close() {
    return new Promise((resolve, reject) => {
        this.connection.end(err => {
            if (err)
                return reject(err);
            resolve();
        });
    });
}
}
module.exports = Database;

然而,这在执行时会继续并打印最终结果(空数组),而无需等待执行子查询。我在 row 和 new_database.query 上尝试了异步等待,但它仍然没有等待子查询执行完成。我可以在这里做什么?

【问题讨论】:

  • 因为appData 是使用new_database.query 的异步结果构建的,并且在.then 中没有返回任何承诺......下一个.then 将被调用得太早 - 你'需要正确使用promises - 也许return new_database.query(.... etc 就足够了
  • 我试过返回,结果还是一样

标签: javascript mysql node.js promise


【解决方案1】:

我改进了sub-queries 的逻辑并使用Promise.all() 重写了它们:

export function getLocations(req, res) {
    let appData = [];
    const database = new Database();
    database.query('select * from districts')
        .then(rows => {

            // create promise list for all sub-queries
            const promise_list = rows.map(row => new Promise((resolve, reject) => {
                const new_database = new Database();
                return new_database.query(`SELECT locations.id,locations.name FROM locations .... WHERE locations.district=?`, row.id)
                    .then(sub_rows => {
                        let district = row;
                        district["locations"] = sub_rows;
                        appData.push(district);
                        new_database.close();
                        resolve(district);
                    }, err => {
                        return new_database.close().then(() => { throw err; })
                    });
            })
            );

            // execute all sub-queries in parallel and wait for them
            Promise.all(promise_list).then(result => {
                res.status(200).json(appData);
                database.close()
            }).catch(err => {
                console.log(err);
                res.status(500).json("Database Error");
            });

        });
}

PS:您可以将appData 声明为const,您只是将数据推入其中。不重新分配它。

【讨论】:

  • 我登录了,现在执行顺序正确,但没有返回并卡住。最终结果没有打印出来,一直在等待。
  • @AnoopKrishnan 从return new_database.close(); 行中删除return,然后添加resolve(district)。我也在编辑答案以使其更清楚。不幸的是,我无法测试它。
【解决方案2】:

使用 JOIN 来尝试获得您想要的结果。可用的功能取决于 MySQL 版本,因此您可能需要 GROUP_CONCAT 而不是 JSON_ARRAYAGG

SELECT districts.*, JSON_ARRAYAGG(locations)
FROM districts
LEFT JOIN locations
   ON locations.district=districts.id
GROUP BY districts.id

Javascript 连接的性能很差,所以让数据库按照它的设计来做吧。

【讨论】:

  • 我在帖子中编辑了我的实际查询。他们不是“可加入的”
猜你喜欢
  • 2017-09-05
  • 2019-05-25
  • 2017-04-08
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 2020-06-19
  • 2019-05-05
  • 1970-01-01
相关资源
最近更新 更多