如何为MySQL查询结果对象添加isLiked字段并返回给客户端?
问题原因及解决方案
核心问题分析
- 异步时序错误:
connectDB.query是异步操作,你在循环中发起的点赞状态查询还未执行完成,就提前调用了res.json(post_result),此时isLiked字段还未被赋值到结果对象中。 - 字段名大小写不一致:代码中同时出现了
isliked(小写d)和isLiked(大写L),导致字段名混乱。 - SQL注入风险:直接通过字符串拼接生成SQL语句(如
${req.user['uid']}),存在严重的安全漏洞。
方案一:单条SQL查询直接获取结果(推荐,性能最优)
通过LEFT JOIN关联post_likes表,用CASE语句一次性判断当前用户的点赞状态,避免多次异步查询的时序问题,同时减少数据库请求次数。
const fetchPost = (req, res, next) => { // 使用参数化查询避免SQL注入,?为占位符 const sql = ` SELECT account.name, account.username, post.content, post.likes, post.visibility, post.date, post.time, post.profile, post.id, CASE WHEN pl.post_id IS NOT NULL THEN TRUE ELSE FALSE END AS isLiked FROM post INNER JOIN account ON account.uid = post.user_id LEFT JOIN post_likes pl ON pl.post_id = post.id AND pl.user_id = (SELECT id FROM account WHERE uid = ?) WHERE post.visibility IN ('Friends', 'Public') `; connectDB.query(sql, [req.user['uid']], (err, post_result) => { if (err) { console.log(err); return next(createCustomError(err, 400)); } res.status(200).json(post_result); }); };
方案二:用Promise + async/await处理异步循环
如果需要保留分步查询的逻辑,可将数据库查询转为Promise,配合async/await和Promise.all确保所有点赞状态查询完成后再返回响应。
const fetchPost = async (req, res, next) => { try { // 1. 查询公开/好友可见的帖子 const postSql = ` SELECT account.name,account.username,post.content,post.likes, post.visibility,post.date,post.time, post.profile, post.id FROM post INNER JOIN account ON account.uid = post.user_id WHERE post.visibility = 'Friends' OR post.visibility = 'Public' `; const [post_result] = await connectDB.promise().query(postSql); // 2. 查询当前用户ID(参数化查询) const getUidSql = `SELECT id FROM account where uid = ?`; const [user_id_result] = await connectDB.promise().query(getUidSql, [req.user['uid']]); const userId = user_id_result[0]['id']; // 3. 批量查询所有帖子的点赞状态 await Promise.all(post_result.map(async (post) => { const likeSql = `SELECT user_id, post_id FROM post_likes WHERE post_id = ? AND user_id = ?`; const [likeResult] = await connectDB.promise().query(likeSql, [post.id, userId]); post.isLiked = likeResult.length > 0; })); // 4. 所有查询完成后返回响应 res.status(200).json(post_result); } catch (err) { console.log(err); return next(createCustomError(err, 400)); } };
关键改进点
- 两种方案均使用参数化查询,彻底规避SQL注入风险。
- 统一字段名为
isLiked,避免大小写混乱。 - 方案一通过单次数据库请求完成所有逻辑,性能远优于多次查询。
内容的提问来源于stack exchange,提问作者Vishal Kumar
相关产品推荐
相关产品推荐

