温嘉琪 / BUILDING SOMETHING FUN

JSON对象和数据嵌套:用n8n来自动化找工作+写cover letter(1)

为什么n8n的数据结构这么复杂?

在n8n中,数据在节点之间传递时会有各种不同的嵌套层级,这主要取决于三个因素:

  1. 数据从哪里来(是HTTP请求、数据库查询还是第三方API)
  2. 前面的节点做了什么处理(比如用了Split节点或者Merge节点)
  3. 节点之间是怎么连接的(比如使用Item Lists还是选择了Iterate)

这种复杂性让我们经常需要"猜测"正确的数据路径,特别是在复杂工作流中。

我的通用解决方案

经过多次踩坑后,我总结出了一段可以解决大多数数据结构问题的代码。这段代码通过尝试多种可能的数据路径来找到我们需要的数据:

// 尝试多种可能的数据结构
try {
    // 方式1: 最常见的数据结构 - 直接从项目列表中获取
    if ($input.item && $input.item[0] && $input.item[0].json && $input.item[0].json.output) {
        jobs = $input.item[0].json.output;
    }
    // 方式2: 使用all()方法获取所有输入
    else if ($input.all()[0].json.output) {
        jobs = $input.all()[0].json.output;
    }
    // 方式3: 使用first()获取第一个项目,但数据在不同位置
    else if ($input.first().json[0] && $input.first().json[0].output) {
        jobs = $input.first().json[0].output;
    }
    // 方式4: 处理额外嵌套的情况
    else {
        // 获取第一个项目的json内容
        jobs = $input.first().json;
        // 检查是否为数组且包含output字段
        if (Array.isArray(jobs) && jobs[0] && jobs[0].output) {
            jobs = jobs[0].output;
        }
    }
} catch (error) {
    // 错误处理: 如果上述所有方法都失败,设置为空数组
    jobs = [];
    console.log('Error accessing job data:', error.message);
}

// 最后验证: 确保jobs确实是一个数组
if (!Array.isArray(jobs)) {
    console.log('Jobs is not an array, trying alternative method');
    // 记录实际数据结构以便调试
    console.log('Actual data structure:', JSON.stringify($input.all()));
    jobs = [];
}

为什么会这么复杂?

我觉得n8n中的数据结构问题主要有几个原因:

  1. 不同来源的数据结构不一致

    • HTTP请求可能返回 { "data": [...] }
    • 数据库节点可能直接返回 [...]
    • 有些节点会将数据包装在 json 属性中
  2. n8n自己的数据表示方式: n8n使用"Item Lists"的概念,通常数据是这样存储的:

    [
      { json: { your: 'data' } },
      { json: { more: 'data' } }
    ]
    
    
  3. 多种数据访问方法: n8n提供了多种访问数据的方法,比如:

    • $input.item[0].json - 直接访问
    • $input.first().json - 使用辅助方法
    • $input.all() - 获取所有数据

我常见的数据结构模式

在使用n8n的过程中,我发现数据通常会以下面几种模式出现:

  1. 标准结构$input.item[0].json.yourData
  2. 数组嵌套$input.item[0].json[0].yourData
  3. 对象嵌套$input.item[0].json.data.yourData
  4. 多层嵌套$input.item[0].json.data[0].items

我的实用建议

以下是我积累的一些小技巧,希望能帮到你:

  1. 使用Debug节点:在Function节点前放一个Debug节点,查看实际的数据结构
  2. 使用Set节点规范化:用Set节点提取并重组数据,创建一致的结构
  3. 使用防御性编码:就像上面的代码那样,尝试多种可能的路径
  4. 多用console.log:记录数据结构,这对调试非常有帮助

简化版本的通用处理

如果你想要一个更简洁的版本,可以试试这个:

// 简化版本
let jobs;
try {
    // 尝试从常见路径获取数据
    const data = $input.first().json;

    // 寻找jobs数组 - 检查常见位置
    if (data.output && Array.isArray(data.output)) {
        jobs = data.output;
    } else if (Array.isArray(data) && data[0]?.output) {
        jobs = data[0].output;
    } else if (data.data?.output) {
        jobs = data.data.output;
    } else {
        // 打印数据结构供调试
        console.log('Data structure:', JSON.stringify(data));
        jobs = [];
    }
} catch (error) {
    console.log('Error:', error.message);
    jobs = [];
}