You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

是否需用Promise处理Node.js路由数据库查询响应?求优化方案

问题描述

我不确定当前的Express路由代码存在什么问题,希望得到指导。我猜测可能需要用Promise等待所有数据推入数组,但不确定有没有更优的处理方式。

代码示例
router.get('/notifications/:user_id', (req, res) => {

    console.log('get comments by ID route received a GET request');

    var user_id = req.params.user_id;
    console.log(user_id)
    
    // 获取用户所有帖子
    var getNotificationsById = 'SELECT user_profiles.forename, user_profiles.surname, user_profiles.profile_image, user_posts.id, user_posts.title, user_posts.price, count(distinct post_comments.id) AS total_comments, sum(post_likes.likes=1) AS total_likes FROM user_posts LEFT JOIN post_comments ON user_posts.id = post_comments.post_id LEFT JOIN post_likes ON user_posts.id = post_likes.post_id LEFT JOIN post_comment_likes ON user_posts.id = post_comment_likes.post_id LEFT JOIN user_profiles ON post_likes.user_id = user_profiles.id WHERE user_posts.user_id = ? GROUP BY user_posts.id ORDER BY user_posts.created DESC'

    // 通过帖子ID获取关联内容
    var getRelationsById = 'SELECT user_profiles.forename, user_profiles.surname, user_profiles.profile_image, user_posts.id, user_posts.title, user_posts.price, count(distinct post_comments.id) AS total_comments, sum(post_likes.likes=1) AS total_likes FROM user_posts LEFT JOIN post_comments ON user_posts.id = post_comments.post_id LEFT JOIN post_likes ON user_posts.id = post_likes.post_id LEFT JOIN post_comment_likes ON user_posts.id = post_comment_likes.post_id LEFT JOIN user_profiles ON post_likes.user_id = user_profiles.id WHERE post_comment_likes.post_id = ? GROUP BY post_comments.id ORDER BY user_posts.created DESC'
    
    var userPostId = [];
    var userResult = [];

    var query = connection.query(getNotificationsById, [user_id], (error, result) => {
        if(error) {
            console.error(error);
            logging.error.error(error);
            return;
        }
        var count = 0
        for(i in result) {
            count++
            console.log('count total = ' + count + ' or more')
            var post_id = result[i].id
            userPostId.push(post_id)

            var query = connection.query(getRelationsById, [post_id], (error, result) => {
                if(error) {
                    console.error(error);
                    logging.error.error(error);
                    return;
                }
                var count = 0
                for(i in result) {
                    count++
                    console.log('data found = ' + count)
                    userResult.push(result)
                }
                console.log(result)
            })
        }
        const message = "Successful"
        res.status(200).json({message: message, status: 200, result: userResult})
    });
})
问题分析与解决方案

核心问题

当前代码的关键问题是异步操作未等待完成就返回响应:

  • connection.query是异步回调函数,外层循环中发起的多次getRelationsById查询还没执行完毕,就已经执行了res.status(200).json(...),此时userResult还没被填充完整,返回的结果是空或不完整。
  • 代码中使用了未声明的全局变量i,会导致循环变量污染,出现逻辑错误。

优化方案

方案1:Promise化查询 + Promise.all 处理异步

先把回调式的connection.query包装成Promise,再用Promise.all等待所有查询完成:

// 包装connection.query为Promise函数
const queryPromise = (sql, params) => {
    return new Promise((resolve, reject) => {
        connection.query(sql, params, (error, result) => {
            if (error) {
                reject(error);
            } else {
                resolve(result);
            }
        });
    });
};

router.get('/notifications/:user_id', async (req, res) => {
    console.log('get comments by ID route received a GET request');
    const user_id = req.params.user_id;
    console.log(user_id);

    const getNotificationsById = 'SELECT user_profiles.forename, user_profiles.surname, user_profiles.profile_image, user_posts.id, user_posts.title, user_posts.price, count(distinct post_comments.id) AS total_comments, sum(post_likes.likes=1) AS total_likes FROM user_posts LEFT JOIN post_comments ON user_posts.id = post_comments.post_id LEFT JOIN post_likes ON user_posts.id = post_likes.post_id LEFT JOIN post_comment_likes ON user_posts.id = post_comment_likes.post_id LEFT JOIN user_profiles ON post_likes.user_id = user_profiles.id WHERE user_posts.user_id = ? GROUP BY user_posts.id ORDER BY user_posts.created DESC';

    const getRelationsById = 'SELECT user_profiles.forename, user_profiles.surname, user_profiles.profile_image, user_posts.id, user_posts.title, user_posts.price, count(distinct post_comments.id) AS total_comments, sum(post_likes.likes=1) AS total_likes FROM user_posts LEFT JOIN post_comments ON user_posts.id = post_comments.post_id LEFT JOIN post_likes ON user_posts.id = post_likes.post_id LEFT JOIN post_comment_likes ON user_posts.id = post_comment_likes.post_id LEFT JOIN user_profiles ON post_likes.user_id = user_profiles.id WHERE post_comment_likes.post_id = ? GROUP BY post_comments.id ORDER BY user_posts.created DESC';

    try {
        // 获取用户所有帖子
        const posts = await queryPromise(getNotificationsById, [user_id]);
        // 为每个帖子生成关联查询的Promise
        const relationPromises = posts.map(post => queryPromise(getRelationsById, [post.id]));
        // 等待所有关联查询完成
        const allRelations = await Promise.all(relationPromises);
        // 合并结果(根据需求调整格式)
        const userResult = allRelations.flat();
        
        res.status(200).json({
            message: "Successful",
            status: 200,
            result: userResult
        });
    } catch (error) {
        console.error(error);
        logging.error.error(error);
        res.status(500).json({
            message: "Error retrieving data",
            status: 500,
            error: error.message
        });
    }
});

方案2:优化SQL查询,减少数据库请求

多次查询会增加性能开销,更优的方式是通过一次SQL关联查询获取所有数据:

router.get('/notifications/:user_id', (req, res) => {
    console.log('get comments by ID route received a GET request');
    const user_id = req.params.user_id;
    console.log(user_id);

    // 合并后的SQL查询,一次获取所有需要的数据
    const sql = `SELECT 
        up.forename, 
        up.surname, 
        up.profile_image, 
        upost.id AS post_id, 
        upost.title, 
        upost.price, 
        COUNT(DISTINCT pc.id) AS total_comments, 
        SUM(pl.likes=1) AS total_likes
    FROM user_posts upost
    LEFT JOIN post_comments pc ON upost.id = pc.post_id
    LEFT JOIN post_likes pl ON upost.id = pl.post_id
    LEFT JOIN post_comment_likes pcl ON upost.id = pcl.post_id
    LEFT JOIN user_profiles up ON pl.user_id = up.id
    WHERE upost.user_id = ?
    GROUP BY upost.id
    ORDER BY upost.created DESC`;

    connection.query(sql, [user_id], (error, result) => {
        if(error) {
            console.error(error);
            logging.error.error(error);
            return res.status(500).json({
                message: "Error retrieving data",
                status: 500,
                error: error.message
            });
        }
        res.status(200).json({
            message: "Successful",
            status: 200,
            result: result
        });
    });
});

额外注意点

  • 变量声明必须使用let/const,避免全局变量污染。
  • 错误处理要完整,所有出错分支都要返回响应,防止请求挂起。

内容的提问来源于stack exchange,提问作者Jay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 14:34:58