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

如何将Node.js(ExpressJS)响应转换为嵌套JSON响应?

我明白你在开发REST API时想要构造嵌套JSON响应的痛点——手动用for循环处理MySQL返回的扁平化结果确实容易出错,而且代码会变得冗余。下面给你几个实用的方案,从手动优化到工具库都有,你可以根据项目复杂度选择:

方案1:手动优化数据结构(适合简单场景)

有时候不是循环本身的问题,而是处理逻辑没理顺。比如假设你有users和posts表,要返回用户带所属帖子的嵌套结构,MySQL查询可能返回的是扁平化的多行结果(每个用户+对应帖子一行),这时候可以用对象来分组:

// 假设MySQL查询返回的结果是这样的扁平化数组
const flatResults = [
  { userId: 1, username: 'Alice', postId: 1, title: 'First Post' },
  { userId: 1, username: 'Alice', postId: 2, title: 'Second Post' },
  { userId: 2, username: 'Bob', postId: 3, title: 'Bob\'s Post' }
];

// 手动分组构建嵌套结构
const nestedData = {};
flatResults.forEach(row => {
  // 如果用户还没在对象里,先初始化
  if (!nestedData[row.userId]) {
    nestedData[row.userId] = {
      userId: row.userId,
      username: row.username,
      posts: []
    };
  }
  // 添加帖子到用户的posts数组
  nestedData[row.userId].posts.push({
    postId: row.postId,
    title: row.title
  });
});

// 转成数组返回给前端
const response = Object.values(nestedData);
console.log(response);

这样就能得到每个用户包含posts数组的嵌套JSON了,比单纯的for循环更清晰,不容易出错。

方案2:使用mysql2的嵌套查询功能

如果你用的是mysql2(比原生mysql库功能更丰富),它支持通过nestTables选项或者rowsAsArray来简化嵌套结构的处理,甚至可以结合JOIN查询直接得到嵌套结果:

比如开启nestTables:

const mysql = require('mysql2/promise');

async function getUsersWithPosts() {
  const connection = await mysql.createConnection({
    host: 'localhost',
    user: 'your-user',
    database: 'your-db',
    nestTables: true // 关键:把不同表的字段嵌套到对象里
  });

  const [rows] = await connection.execute(
    'SELECT users.*, posts.* FROM users LEFT JOIN posts ON users.id = posts.user_id'
  );

  // 然后再用分组逻辑处理,因为JOIN还是会返回多行,但字段已经按表分组了
  const nestedData = {};
  rows.forEach(row => {
    const user = row.users;
    const post = row.posts;
    if (!nestedData[user.id]) {
      nestedData[user.id] = { ...user, posts: [] };
    }
    if (post.id) { // 排除没有帖子的用户的空post对象
      nestedData[user.id].posts.push(post);
    }
  });

  return Object.values(nestedData);
}

mysql2还有execute方法支持参数绑定,比原生更安全,嵌套表字段的功能也能减少字段名冲突的问题。

方案3:使用ORM框架(适合复杂项目)

如果你的API涉及多个表关联,推荐用ORM来简化嵌套查询,比如Sequelize或者Prisma,它们都支持关联查询直接返回嵌套JSON:

比如用Sequelize的示例:
首先定义模型关联:

// User模型
const User = sequelize.define('User', {
  username: DataTypes.STRING
});

// Post模型
const Post = sequelize.define('Post', {
  title: DataTypes.STRING
});

// 建立关联:一个用户有多个帖子
User.hasMany(Post, { foreignKey: 'userId' });
Post.belongsTo(User);

然后查询时直接包含关联的帖子:

async function getUsersWithPosts() {
  const users = await User.findAll({
    include: [Post] // 直接包含关联的Post模型,自动返回嵌套结构
  });
  return users.map(user => user.toJSON()); // 转成普通JSON对象返回给前端
}

这样Sequelize会自动帮你处理JOIN和嵌套结构,代码非常简洁,而且还能处理更复杂的关联(比如多对多、嵌套关联)。

方案4:使用查询构建器Knex.js

如果你不想用ORM,但又想简化查询和嵌套处理,可以用Knex.js,它支持join和select时的字段别名,结合分组逻辑也能轻松得到嵌套结构:

const knex = require('knex')({
  client: 'mysql',
  connection: {
    host: 'localhost',
    user: 'your-user',
    database: 'your-db'
  }
});

async function getUsersWithPosts() {
  const rows = await knex('users')
    .leftJoin('posts', 'users.id', 'posts.user_id')
    .select('users.*', 'posts.id as post_id', 'posts.title as post_title');

  // 同样用分组逻辑处理成嵌套结构
  const nestedData = {};
  rows.forEach(row => {
    const userId = row.id;
    if (!nestedData[userId]) {
      nestedData[userId] = {
        id: row.id,
        username: row.username,
        posts: []
      };
    }
    if (row.post_id) {
      nestedData[userId].posts.push({
        id: row.post_id,
        title: row.post_title
      });
    }
  });

  return Object.values(nestedData);
}

总结一下:如果是简单的关联,手动分组或者用mysql2的nestTables就足够;如果项目关联复杂,ORM(Sequelize/Prisma)能帮你省很多事,代码也更易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:06:02