
本文介绍如何基于 json 路径(如 `$.offer.custom_fields.job_title`)自动提取嵌套对象的所有可映射字段,并与预定义的字段映射配置进行匹配,生成包含 `externalfieldid` 和对应 `integrationfieldid` 的标准化映射列表,缺失映射则置为空字符串。
在构建集成系统(如 HRIS ↔ ATS 数据同步)时,常需将源对象(如 API 响应)的嵌套字段路径与目标系统字段(如 $.engagementData.title)建立双向映射关系。本教程提供一种轻量、可复用的 TypeScript 方案,用于自动发现源对象所有深层字段路径,并精确匹配预设的映射规则,最终生成符合预期结构的映射清单。
✅ 核心步骤说明
- 递归提取所有字段路径:使用深度优先遍历,将嵌套对象转为标准 JSONPath 格式(如 $.offer.custom_fields.job_title);
- 匹配映射配置:遍历每个提取出的 externalFieldId,查找 defaultFieldMapping 中 path 值完全相等的条目,获取其 key(即 integrationFieldId);
- 补全未映射字段:对源对象中存在但未在 defaultFieldMapping 中声明的字段(如 $.offer.job_post),保留其路径并设置 integrationFieldId: ''。
? 实现代码(TypeScript 兼容)
function getDeepKeys(obj: Record<string, any>): string[] {
function* _getDeepKeys(
current: Record<string, any>,
prefix: string
): Generator<string> {
for (const [key, value] of Object.entries(current)) {
const path = `${prefix}${key}`;
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
yield* _getDeepKeys(value, `${path}.`);
} else {
yield path;
}
}
}
return [..._getDeepKeys(obj, '$.')];
}
// 示例数据
const response = {
offer: {
custom_fields: {
job_title: 'engineer',
},
starts_at: 'test',
job_post: 'test',
},
};
const defaultFieldMapping = {
'$.engagementData.title': {
default: 'Software Engineer',
path: '$.offer.custom_fields.job_title',
fieldName: 'Title',
},
'$.engagementData.startDateUTC': {
default: null,
path: '$.offer.starts_at',
},
};
// 生成映射结果
const result = getDeepKeys(response).map(externalFieldId => {
const matchedEntry = Object.entries(defaultFieldMapping).find(
([_, config]) => config.path === externalFieldId
);
return {
externalFieldId,
integrationFieldId: matchedEntry ? matchedEntry[0] : '',
};
});
console.log(result);
// 输出:
// [
// { externalFieldId: "$.offer.custom_fields.job_title", integrationFieldId: "$.engagementData.title" },
// { externalFieldId: "$.offer.starts_at", integrationFieldId: "$.engagementData.startDateUTC" },
// { externalFieldId: "$.offer.job_post", integrationFieldId: "" }
// ]⚠️ 注意事项
- 路径格式一致性:确保 response 对象的字段路径与 defaultFieldMapping.path 完全一致(包括 $. 前缀和点号分隔),否则匹配失败;
- 避免数组干扰:当前 getDeepKeys 默认跳过数组(因 JSONPath 中数组索引需显式处理,如 $.items[0].name),如需支持数组,请扩展逻辑以识别 Array.isArray(value) 并递归处理各元素;
- 性能考量:对于超深或超大嵌套对象,建议增加递归深度限制或改用栈式迭代实现;
-
TypeScript 类型增强(推荐):
interface FieldMappingConfig { default: any; path: string; fieldName?: string; } type FieldMapping = Record<string, FieldMappingConfig>;
该方案简洁可靠,无需外部依赖,可直接集成至数据适配层、ETL 配置工具或低代码映射编辑器中,显著提升字段映射的自动化程度与可维护性。










