请问如何解决Nodejs中node-mysql多层回调的问题

请问如何解决Nodejs中node-mysql多层回调的问题

例如:

table_user: userId, userName
table_user_course: userId, courseName

现在我想通过node获得这样的结果:

[
    {
        "userID": 1,
        "userName": "mark",
        "userCourse": [
            {
                "courseName": "math"
            },
            ...
        ]
    },
    ...
]

我是准备这样解决的:

// require("mysql");
// mysql connection

var resData = null;

mysql.query({
    sql: 'SELECT * FROM table_user'
}, function(err, rows) {
    // if rows && rows.length>0 
    var usersInfo = [];
    for (var row in rows) {
        var userInfo = {
            userId: row.userId,
            userName: row.userName,
            userCourse: []
        };
        mysql.query({
            sql: 'SELECT * FROM table_course WHERE userID = '+row.userId
        }, function(err, rows) {
            /* 这里怎么把获取的信息返回给上面的userInfo.userCourse */
        });
        usersInfo.push(userInfo);
    }
    /* 这里怎么把最后的usersInfo赋值给resData */
    resData = usersInfo;
});

/* 上面的有很多是伪代码,怕文字表述不清才这样写的,所以大家不要在意个别小错误=。= */

所以请问:

  1. async是可以解决单次依赖,那循环多次那块应该怎么办?可以继续用async解决问题吗?
  2. 有其他办法或途径可以解决吗?比如能否用sql语句直接解决问题==#

谢谢大家…


5 回复

要解决Node.js中node-mysql多层回调的问题,我们可以使用async/await语法来简化异步操作,并且让代码更易读。此外,我们还可以优化SQL查询以减少数据库往返次数。以下是解决方案:

使用 async/await

首先,我们需要确保我们的MySQL库支持async/await。如果你使用的是标准的mysql库,你可能需要引入util.promisify来将回调风格的API转换为Promise风格。

const mysql = require('mysql');
const util = require('util');

const pool = mysql.createPool({
    host: 'localhost',
    user: 'root',
    password: 'password',
    database: 'database_name'
});

const query = util.promisify(pool.query).bind(pool);

async function getUserCourses() {
    try {
        const users = await query('SELECT * FROM table_user');
        
        const usersWithCourses = await Promise.all(users.map(async user => {
            const courses = await query('SELECT * FROM table_user_course WHERE userId = ?', [user.userId]);
            return {
                userId: user.userId,
                userName: user.userName,
                userCourse: courses.map(course => ({
                    courseName: course.courseName
                }))
            };
        }));
        
        console.log(usersWithCourses);
        return usersWithCourses;
    } catch (error) {
        console.error(error);
    }
}

getUserCourses();

使用联合查询(JOIN)

为了减少数据库往返次数,你可以考虑使用SQL中的JOIN来一次性获取所有数据。这可以通过在SQL查询中使用JOIN来实现。

SELECT u.userId, u.userName, c.courseName
FROM table_user u
LEFT JOIN table_user_course c ON u.userId = c.userId;

然后在Node.js中处理结果:

async function getUserCourses() {
    try {
        const results = await query(`
            SELECT u.userId, u.userName, c.courseName
            FROM table_user u
            LEFT JOIN table_user_course c ON u.userId = c.userId
        `);
        
        const groupedResults = results.reduce((acc, current) => {
            const existingUser = acc.find(user => user.userId === current.userId);
            if (existingUser) {
                existingUser.userCourse.push({ courseName: current.courseName });
            } else {
                acc.push({
                    userId: current.userId,
                    userName: current.userName,
                    userCourse: [{ courseName: current.courseName }]
                });
            }
            return acc;
        }, []);

        console.log(groupedResults);
        return groupedResults;
    } catch (error) {
        console.error(error);
    }
}

这两种方法都可以有效地解决多层回调的问题,并提高代码的可读性和性能。选择哪种方法取决于你的具体需求和数据库设计。


select a.userId, a.userName, b.courseName from table_user a join table_user_course b on a.userId=b.userId;

楼主好好补补 SQL。。。。

async 有很多方法啊…应该有可以解决的…

恩,谢谢,确实没怎么仔细研究过join,这样确实可以在第一次执行sql的时候获取到所有想要的信息。那如果某个场景下需要执行两次sql,并且第二次依赖于第一次的结果应该怎样处理呢?

要解决Node.js中node-mysql多层回调的问题,可以使用async/await来简化异步代码,并且避免回调地狱(callback hell)。以下是两种解决方案:一种使用async/await,另一种使用SQL联接。

使用async/await

首先需要安装mysqlasync库:

npm install mysql async

然后你可以使用以下代码来解决这个问题:

const mysql = require('mysql');
const async = require('async');

const connection = mysql.createConnection({
    host: 'localhost',
    user: 'your_username',
    password: 'your_password',
    database: 'your_database'
});

connection.connect();

async function getUsersWithCourses() {
    const [rows] = await new Promise((resolve, reject) => {
        connection.query('SELECT * FROM table_user', (err, rows) => {
            if (err) return reject(err);
            resolve(rows);
        });
    });

    const usersInfo = await Promise.all(rows.map(async (row) => {
        const [courses] = await new Promise((resolve, reject) => {
            connection.query('SELECT * FROM table_user_course WHERE userId = ?', [row.userId], (err, rows) => {
                if (err) return reject(err);
                resolve(rows);
            });
        });

        return {
            userId: row.userId,
            userName: row.userName,
            userCourse: courses.map(course => ({
                courseName: course.courseName
            }))
        };
    }));

    console.log(usersInfo);
}

getUsersWithCourses().catch(console.error);

connection.end();

使用SQL联接

另一种解决方案是通过一次查询完成所有操作,使用SQL联接将两个表的数据合并到一个查询结果中。这可以通过以下SQL语句实现:

SELECT u.userId, u.userName, c.courseName
FROM table_user u
LEFT JOIN table_user_course c ON u.userId = c.userId
ORDER BY u.userId;

然后在Node.js代码中执行此查询:

const mysql = require('mysql');

const connection = mysql.createConnection({
    host: 'localhost',
    user: 'your_username',
    password: 'your_password',
    database: 'your_database'
});

connection.connect();

connection.query(`
    SELECT u.userId, u.userName, c.courseName
    FROM table_user u
    LEFT JOIN table_user_course c ON u.userId = c.userId
    ORDER BY u.userId;
`, (err, rows) => {
    if (err) throw err;

    const usersInfo = {};
    rows.forEach(row => {
        if (!usersInfo[row.userId]) {
            usersInfo[row.userId] = {
                userId: row.userId,
                userName: row.userName,
                userCourse: []
            };
        }
        if (row.courseName) {
            usersInfo[row.userId].userCourse.push({ courseName: row.courseName });
        }
    });

    console.log(Object.values(usersInfo));
});

connection.end();

以上两种方法都可以有效解决多层回调的问题。选择哪种方法取决于你的具体需求和数据库设计。

回到顶部