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

如何在Sequelize.js中无需外键关联获取嵌套JSON数组

Alright, let's figure out how to get that nested JSON structure with Sequelize even without foreign key associations set up between your user and region tables. There are two solid approaches here—using raw SQL queries (efficient for direct database-level aggregation) or fetching data separately and manually nesting it in JavaScript. Let's break both down.


Approach 1: Use Raw SQL Queries with Database JSON Functions

Since you don't have model associations, raw queries let you leverage your database's built-in JSON aggregation functions to directly generate the nested structure. The exact syntax varies slightly by database, so here are examples for PostgreSQL and MySQL:

For PostgreSQL

We'll use JSON_AGG and JSON_BUILD_OBJECT to aggregate users under their respective regions:

const { sequelize } = require('./your-sequelize-instance'); // Import your Sequelize instance

async function getNestedRegionsWithUsers() {
  const rawQuery = `
    SELECT 
      r.region_id,
      r.region_name,
      JSON_AGG(
        JSON_BUILD_OBJECT(
          'user_id', u.user_id,
          'user_name', u.user_name
        )
      ) AS users
    FROM region r
    LEFT JOIN "user" u ON r.region_id = u.region_id
    GROUP BY r.region_id, r.region_name;
  `;

  // Execute the query and return the result
  const nestedData = await sequelize.query(rawQuery, { type: sequelize.QueryTypes.SELECT });
  return nestedData;
}

// Test the function
getNestedRegionsWithUsers().then(data => console.log(JSON.stringify(data, null, 2)));

For MySQL

Use JSON_ARRAYAGG and JSON_OBJECT instead. Note that MySQL returns null for regions with no users, so we'll map the result to replace null with an empty array:

const { sequelize } = require('./your-sequelize-instance');

async function getNestedRegionsWithUsers() {
  const rawQuery = `
    SELECT 
      r.region_id,
      r.region_name,
      JSON_ARRAYAGG(
        JSON_OBJECT(
          'user_id', u.user_id,
          'user_name', u.user_name
        )
      ) AS users
    FROM region r
    LEFT JOIN user u ON r.region_id = u.region_id
    GROUP BY r.region_id, r.region_name;
  `;

  const rawResult = await sequelize.query(rawQuery, { type: sequelize.QueryTypes.SELECT });
  // Clean up null users arrays
  return rawResult.map(item => ({
    ...item,
    users: item.users || []
  }));
}

// Test the function
getNestedRegionsWithUsers().then(data => console.log(JSON.stringify(data, null, 2)));

Approach 2: Fetch Data Separately & Manually Nest in JavaScript

If you prefer to avoid raw SQL, you can fetch regions and users separately, then use JavaScript to group users under their regions. This approach is database-agnostic:

const Region = require('./models/Region'); // Import your Region model
const User = require('./models/User'); // Import your User model

async function getNestedRegionsWithUsers() {
  // Step 1: Fetch all regions (only the fields we need)
  const regions = await Region.findAll({
    attributes: ['region_id', 'region_name']
  });

  // Step 2: Fetch all users (include region_id to map later)
  const users = await User.findAll({
    attributes: ['user_id', 'user_name', 'region_id']
  });

  // Step 3: Group users by their region_id
  const usersByRegion = users.reduce((grouped, user) => {
    const regionId = user.region_id;
    if (!grouped[regionId]) grouped[regionId] = [];
    grouped[regionId].push({
      user_id: user.user_id,
      user_name: user.user_name
    });
    return grouped;
  }, {});

  // Step 4: Nest users into their corresponding regions
  const nestedResult = regions.map(region => ({
    region_id: region.region_id,
    region_name: region.region_name,
    users: usersByRegion[region.region_id] || [] // Fallback to empty array if no users
  }));

  return nestedResult;
}

// Test the function
getNestedRegionsWithUsers().then(data => console.log(JSON.stringify(data, null, 2)));

While you asked for a solution without associations, setting them up will make this process much cleaner long-term. Here's how to define the one-to-many relationship:

In your Region model:

Region.hasMany(User, {
  foreignKey: 'region_id',
  sourceKey: 'region_id',
  as: 'users' // Alias for the association
});

In your User model:

User.belongsTo(Region, {
  foreignKey: 'region_id',
  targetKey: 'region_id',
  as: 'region' // Alias for the association
});

Now you can fetch nested data directly with include:

const nestedResult = await Region.findAll({
  attributes: ['region_id', 'region_name'],
  include: [{
    model: User,
    as: 'users',
    attributes: ['user_id', 'user_name'] // Only fetch the user fields we need
  }]
});

console.log(JSON.stringify(nestedResult, null, 2));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:14:53