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

PHP:如何将子资源JSON合并到主JSON指定关联字段

修正mergeSubResources函数实现关联资源合并

核心逻辑梳理

要实现关联资源的正确合并,核心是基于外键关系建立主资源与子资源的映射,通过索引化子资源提升匹配效率,同时覆盖一对一、一对多两种关联场景。

假设变量结构示例

先明确输入数据的典型结构,方便理解函数逻辑:

// $tablesStructures:定义表间外键关系
const $tablesStructures = {
  Seasons: {
    foreignKeys: {
      genre_id: {
        targetTable: 'Genres',
        targetKey: 'id'
      }
    }
  },
  Genres: {
    // 若需要一对多(Genre对应多个Season),可在这里定义反向关联的外键映射
  }
};

// $subRes:待合并的关联资源集合
const $subRes = {
  Genres: [
    { id: 1, name: 'Action' },
    { id: 2, name: 'Drama' }
  ]
};

// mainJson:主资源JSON
const mainJson = {
  Seasons: [
    { id: 101, title: 'Season 1', genre_id: 1 },
    { id: 102, title: 'Season 2', genre_id: 2 }
  ]
};

修正后的mergeSubResources函数

function mergeSubResources(mainJson, subRes, tablesStructures) {
  // 1. 为子资源创建索引Map,快速通过ID查找单个资源
  const subResourceIndexes = {};
  // 2. 为一对多场景创建按父ID分组的子资源映射
  const subResourcesGroupedByParent = {};

  // 预处理子资源,构建索引和分组
  for (const [tableName, items] of Object.entries(subRes)) {
    // 构建单资源索引
    subResourceIndexes[tableName] = new Map(items.map(item => [item.id, item]));

    // 构建一对多分组(基于子表的外键定义)
    const tableSchema = tablesStructures[tableName];
    if (tableSchema?.foreignKeys) {
      for (const [foreignKey, relation] of Object.entries(tableSchema.foreignKeys)) {
        const groupKey = `${relation.targetTable}_${tableName}`;
        subResourcesGroupedByParent[groupKey] = subResourcesGroupedByParent[groupKey] || new Map();
        
        items.forEach(item => {
          const parentId = item[foreignKey];
          if (!parentId) return;
          
          if (!subResourcesGroupedByParent[groupKey].has(parentId)) {
            subResourcesGroupedByParent[groupKey].set(parentId, []);
          }
          subResourcesGroupedByParent[groupKey].get(parentId).push(item);
        });
      }
    }
  }

  // 遍历主资源,合并关联子资源
  for (const [mainTable, mainItems] of Object.entries(mainJson)) {
    const mainTableSchema = tablesStructures[mainTable];

    // 处理一对一关联:主资源通过外键指向子资源
    if (mainTableSchema?.foreignKeys) {
      for (const [foreignKey, relation] of Object.entries(mainTableSchema.foreignKeys)) {
        const targetTable = relation.targetTable;
        const targetIndex = subResourceIndexes[targetTable];
        if (!targetIndex) continue;

        mainItems.forEach(item => {
          const targetId = item[foreignKey];
          if (targetId == null) return;
          // 将子资源合并到主资源的对应字段(字段名可根据需求调整,这里用目标表名)
          item[targetTable] = targetIndex.get(targetId);
        });
      }
    }

    // 处理一对多关联:多个子资源通过外键指向主资源
    const relatedSubTable = Object.keys(subRes).find(table => {
      return tablesStructures[table]?.foreignKeys?.some(fk => fk.targetTable === mainTable);
    });
    if (relatedSubTable) {
      const groupKey = `${mainTable}_${relatedSubTable}`;
      const groupedSubs = subResourcesGroupedByParent[groupKey];
      if (groupedSubs) {
        mainItems.forEach(item => {
          item[relatedSubTable] = groupedSubs.get(item.id) || [];
        });
      }
    }
  }

  return mainJson;
}

关键修正点

  • 索引化子资源:用Map存储子资源,避免每次匹配都遍历数组,大幅提升性能
  • 覆盖两种关联场景:同时支持一对一(主→子)和一对多(子→主)的合并逻辑
  • 空值处理:跳过无外键值的主资源项,避免出现无效合并
  • 可扩展性:字段名、关联规则可根据实际业务需求调整

调用示例

const mergedResult = mergeSubResources(mainJson, $subRes, $tablesStructures);
console.log(mergedResult);
// 输出结果:
// {
//   Seasons: [
//     { id: 101, title: 'Season 1', genre_id: 1, Genres: { id: 1, name: 'Action' } },
//     { id: 102, title: 'Season 2', genre_id: 2, Genres: { id: 2, name: 'Drama' } }
//   ]
// }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 22:24:56