일. 8월 17th, 2025

데이터는 현대 비즈니스의 심장입니다. 마케팅 자동화, 고객 지원, 내부 시스템 통합 등 모든 과정에서 데이터를 수집하고, 분석하고, 다른 시스템으로 전달해야 합니다. 하지만 이 데이터를 원하는 형태로 가공하는 일은 결코 쉽지 않습니다. 특히 여러 소스에서 들어온 데이터의 형식이 제각각이거나, 복잡한 조건에 따라 데이터를 변환해야 할 때는 더욱 그렇습니다.

n8n은 이런 데이터 워크플로우를 자동화하는 강력한 도구이며, 대부분의 데이터 변환은 Set, Merge, Split 등의 기본 노드로 충분합니다. 하지만 때로는 이런 기본 노드만으로는 해결할 수 없는 복잡하고, 고도로 맞춤화된 로직이 필요할 때가 있습니다. 바로 이때 빛을 발하는 것이 Function 노드입니다! ✨


💡 n8n Function 노드란 무엇인가요?

Function 노드는 n8n 워크플로우 내에서 JavaScript 코드를 직접 작성하고 실행할 수 있게 해주는 특별한 노드입니다. 마치 n8n 워크플로우 안에 작은 ‘프로그래밍 엔진’을 심는 것과 같습니다. 이 노드를 사용하면 n8n의 표준 기능으로는 어려운 모든 종류의 데이터 조작, 계산, 조건부 로직, 그리고 복잡한 데이터 구조 변환 등을 자유롭게 구현할 수 있습니다.

언제 Function 노드를 사용해야 할까요?

  • 표준 노드로는 처리하기 어려운 복잡한 조건부 로직이 필요할 때.
  • 데이터를 특정 수학적 공식에 따라 계산해야 할 때.
  • 다양한 필드를 조합하거나 분리하는 고급 문자열 조작이 필요할 때.
  • 배열이나 객체를 동적으로 추가, 제거, 변형해야 할 때.
  • 여러 아이템의 데이터를 집계하거나 요약해야 할 때.
  • 외부 라이브러리 없이 간단한 유틸리티 함수가 필요할 때.

🛠️ Function 노드의 기본 사용법

Function 노드는 들어오는 데이터를 받아 JavaScript 코드를 실행한 후, 그 결과물을 다음 노드로 전달합니다. 핵심 개념은 다음과 같습니다:

  1. 입력 데이터 접근:

    • $json.items: 이 변수는 현재 Function 노드로 들어오는 모든 아이템(워크플로우의 각 항목)을 담고 있는 배열입니다. 각 아이템은 JSON 객체 형태로 되어 있습니다.
    • $json.items[0].json: 만약 단일 아이템에 접근하거나, 특정 아이템의 원본 JSON 데이터에 직접 접근하고 싶을 때 사용합니다.
    • $items: n8n v1.0부터는 Function 노드에서 입력 데이터를 다룰 때 $items를 사용하는 것이 더 간결하고 일반적입니다. $items는 각 입력 항목을 나타내는 배열이며, 각 항목은 json 속성을 통해 실제 데이터를 가집니다. (예: item.json.myField)
  2. 출력 데이터 반환:

    • Function 노드는 항상 아이템(Item)들의 배열을 반환해야 합니다. 각 아이템은 json 속성 내에 최종적으로 전달하고 싶은 데이터를 포함해야 합니다.
    • 일반적인 반환 형식은 return items; 입니다. 여기서 items[{ json: { /* 데이터 */ } }, { json: { /* 다른 데이터 */ } }]와 같은 형태의 배열입니다.

기본적인 코드 구조:

// 입력으로 들어오는 아이템들을 순회하며 새로운 아이템 배열을 만듭니다.
const newItems = [];

// $json.items (또는 n8n v1.0+ 에서는 $items) 를 순회합니다.
// 예시: item은 { json: { "id": 1, "name": "John" } } 형태입니다.
for (const item of $json.items) { // 또는 for (const item of $items) {
  const originalData = item.json; // 실제 데이터에 접근

  // 여기에 원하는 데이터 변환 로직을 작성합니다.
  const transformedData = {
    // 예시: 원본 데이터에 새로운 필드를 추가
    originalId: originalData.id,
    processedName: originalData.name.toUpperCase()
  };

  // 변환된 데이터를 새 아이템 배열에 추가합니다.
  newItems.push({
    json: transformedData
  });
}

// 최종적으로 변환된 아이템 배열을 반환합니다.
return newItems;

🧩 실용적인 Function 노드 활용 예시

이제 몇 가지 실제 시나리오를 통해 Function 노드가 얼마나 유용한지 살펴보겠습니다.

1. 데이터 정제 및 형식 변경 🧹

사용자 이름의 대소문자를 통일하고, 나이에 따라 ‘성인’, ‘미성년’ 카테고리를 추가하는 등 데이터를 표준화해야 할 때 유용합니다.

✅ 시나리오: 사용자 목록 데이터에서 이름의 첫 글자는 대문자로, 나머지는 소문자로 바꾸고, 나이에 따라 ‘성인’ 또는 ‘미성년’ 카테고리를 부여합니다.

➡️ 입력 데이터 (예시):

[
  { "first_name": "john", "last_name": "DOE", "age": 30 },
  { "first_name": "anna", "last_name": "SMITH", "age": 15 },
  { "first_name": "peter", "last_name": "JONES", "age": 5 }
]

💻 Function 노드 코드:

const newItems = [];

for (const item of $json.items) {
  const originalData = item.json;

  const firstName = originalData.first_name.charAt(0).toUpperCase() + originalData.first_name.slice(1).toLowerCase();
  const lastName = originalData.last_name.charAt(0).toUpperCase() + originalData.last_name.slice(1).toLowerCase();
  const fullName = `${firstName} ${lastName}`; // 전체 이름 조합

  const ageCategory = originalData.age >= 18 ? '성인' : '미성년'; // 나이에 따른 카테고리 분류

  newItems.push({
    json: {
      fullName: fullName,
      ageCategory: ageCategory,
      originalAge: originalData.age // 원본 나이도 포함할 수 있습니다.
    }
  });
}

return newItems;

⬅️ 출력 데이터 (예시):

[
  { "fullName": "John Doe", "ageCategory": "성인", "originalAge": 30 },
  { "fullName": "Anna Smith", "ageCategory": "미성년", "originalAge": 15 },
  { "fullName": "Peter Jones", "ageCategory": "미성년", "originalAge": 5 }
]

2. 조건부 필터링 및 데이터 추가 🚦

특정 조건(예: 주문 금액이 100달러 이상)을 만족하는 데이터만 필터링하고, 동시에 새로운 상태 값을 추가하고 싶을 때 유용합니다.

✅ 시나리오: 온라인 쇼핑몰 주문 내역에서 주문 금액이 50,000원 이상인 주문만 필터링하고, 해당 주문에 isLargeOrder: true 필드를 추가합니다.

➡️ 입력 데이터 (예시):

[
  { "orderId": "ORD001", "amount": 35000, "status": "Pending" },
  { "orderId": "ORD002", "amount": 75000, "status": "Processing" },
  { "orderId": "ORD003", "amount": 48000, "status": "Completed" }
]

💻 Function 노드 코드:

const newItems = [];
const MIN_AMOUNT = 50000; // 최소 금액 기준

for (const item of $json.items) {
  const originalData = item.json;

  if (originalData.amount >= MIN_AMOUNT) { // 조건부 필터링
    newItems.push({
      json: {
        ...originalData, // 기존 모든 필드를 유지하면서
        isLargeOrder: true, // 새로운 필드 추가
        processedAt: new Date().toISOString() // 현재 시간 추가
      }
    });
  }
}

return newItems;

⬅️ 출력 데이터 (예시):

[
  { "orderId": "ORD002", "amount": 75000, "status": "Processing", "isLargeOrder": true, "processedAt": "2023-10-27T10:00:00.000Z" }
]

(날짜는 실행 시점에 따라 달라집니다.)

3. 여러 아이템 합계 및 요약 📊

여러 개의 데이터 항목을 하나의 요약된 정보로 변환해야 할 때 (예: 각 제품 카테고리별 총 판매액 계산) 강력합니다.

✅ 시나리오: 특정 기간 동안 발생한 제품 판매 기록에서 각 제품 카테고리별 총 판매액을 계산합니다.

➡️ 입력 데이터 (예시):

[
  { "product": "티셔츠", "category": "의류", "price": 25000, "quantity": 2 },
  { "product": "신발", "category": "신발", "price": 80000, "quantity": 1 },
  { "product": "청바지", "category": "의류", "price": 45000, "quantity": 1 },
  { "product": "모자", "category": "악세서리", "price": 15000, "quantity": 3 },
  { "product": "스니커즈", "category": "신발", "price": 60000, "quantity": 1 }
]

💻 Function 노드 코드:

const categorySales = {};

for (const item of $json.items) {
  const originalData = item.json;
  const category = originalData.category;
  const totalPrice = originalData.price * originalData.quantity; // 각 아이템의 총액 계산

  if (categorySales[category]) {
    categorySales[category] += totalPrice; // 기존 카테고리에 합산
  } else {
    categorySales[category] = totalPrice; // 새로운 카테고리 추가
  }
}

// 요약된 객체를 n8n 아이템 배열 형식으로 변환합니다.
const newItems = [];
for (const category in categorySales) {
  newItems.push({
    json: {
      category: category,
      totalSales: categorySales[category]
    }
  });
}

return newItems;

⬅️ 출력 데이터 (예시):

[
  { "category": "의류", "totalSales": 95000 },
  { "category": "신발", "totalSales": 140000 },
  { "category": "악세서리", "totalSales": 45000 }
]

4. 중첩된 배열에서 특정 데이터 추출 📦

복잡한 JSON 구조 안에 있는 특정 배열에서 필요한 정보만 뽑아내 새로운 아이템으로 만들 수 있습니다.

✅ 시나리오: 고객 데이터에 중첩된 contacts 배열이 있고, 여기서 type이 ’email’인 연락처의 value만 추출하여 각 이메일을 별도의 아이템으로 만듭니다.

➡️ 입력 데이터 (예시):

[
  {
    "id": 101,
    "name": "Alice",
    "contacts": [
      { "type": "phone", "value": "123-4567" },
      { "type": "email", "value": "alice@example.com" }
    ]
  },
  {
    "id": 102,
    "name": "Bob",
    "contacts": [
      { "type": "email", "value": "bob@example.com" },
      { "type": "email", "value": "bob.work@example.com" }
    ]
  },
  {
    "id": 103,
    "name": "Charlie",
    "contacts": []
  }
]

💻 Function 노드 코드:

const emailsExtracted = [];

for (const item of $json.items) {
  const originalData = item.json;

  // contacts 필드가 존재하고 배열인지 확인합니다.
  if (originalData.contacts && Array.isArray(originalData.contacts)) {
    for (const contact of originalData.contacts) {
      // 연락처 타입이 'email'이고 값이 비어있지 않은지 확인합니다.
      if (contact.type === 'email' && contact.value) {
        emailsExtracted.push({
          json: {
            customerId: originalData.id,
            customerName: originalData.name,
            emailAddress: contact.value
          }
        });
      }
    }
  }
}

return emailsExtracted;

⬅️ 출력 데이터 (예시):

[
  { "customerId": 101, "customerName": "Alice", "emailAddress": "alice@example.com" },
  { "customerId": 102, "customerName": "Bob", "emailAddress": "bob@example.com" },
  { "customerId": 102, "customerName": "Bob", "emailAddress": "bob.work@example.com" }
]

🚀 Function 노드를 효율적으로 사용하는 팁!

  • 작게 시작하고 점진적으로 확장하세요: 한 번에 모든 것을 만들려 하지 말고, 작은 변환부터 시작하여 점차 복잡한 로직을 추가해나가세요.
  • console.log()를 적극 활용하세요: 코드 중간중간에 console.log(변수이름);을 넣어 변수의 현재 값을 확인하면 디버깅에 큰 도움이 됩니다. n8n 실행 로그에서 결과를 볼 수 있습니다.
  • 다른 노드로 가능한지 먼저 검토하세요: Function 노드는 강력하지만, 가능한 경우 Set, Merge, Split 등 더 단순한 노드를 사용하는 것이 워크플로우를 더 읽기 쉽고 유지보수하기 쉽게 만듭니다.
  • 주석을 달아 코드를 설명하세요: 복잡한 로직일수록 코드에 주석을 달아 어떤 작업을 하는지, 왜 그렇게 하는지 설명해두면 나중에 자신이나 다른 사람이 코드를 이해하는 데 큰 도움이 됩니다.
  • 변수 이름을 명확하게 지정하세요: a, b, c 대신 customerData, transformedOrder 등 의미 있는 이름을 사용하면 코드 가독성이 높아집니다.

맺음말 ✨

n8n Function 노드는 단순한 코드 실행을 넘어, 복잡한 로직과 무궁무진한 가능성을 워크플로우에 불어넣는 강력한 도구입니다. 처음에는 JavaScript 코드를 작성하는 것이 어렵게 느껴질 수 있지만, 위에 제시된 예시와 팁을 활용하여 조금씩 연습하다 보면 어느새 복잡한 데이터 변환도 손쉽게 처리할 수 있게 될 것입니다.

이제 두려워 말고 Function 노드를 활용하여 여러분의 n8n 워크플로우를 한 단계 더 업그레이드해보세요! 궁금한 점이 있다면 언제든지 n8n 커뮤니티나 관련 자료를 찾아보시길 바랍니다. 행복한 자동화 생활 되세요! 😊 D

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다