안녕하세요, n8n으로 자동화를 한 단계 업그레이드하고 싶은 여러분! 🌟
n8n은 복잡한 워크플로우를 시각적으로 구축할 수 있게 해주지만, 진정한 자동화의 힘은 바로 데이터 변환 능력에서 나옵니다. API에서 받은 데이터를 원하는 형태로 가공하거나, 여러 소스의 데이터를 하나로 합치고, 특정 조건에 따라 데이터를 분리하는 등 다양한 시나리오에서 데이터 변환은 필수적입니다.
이번 글에서는 n8n에서 가장 중요하고 강력한 데이터 구조인 JSON과 배열(Array)을 자유자재로 다루고, 반복적인 작업을 효율적으로 처리하는 루프(Loop) 활용법까지, n8n 고급 데이터 변환의 모든 것을 깊이 있게 다뤄보겠습니다. 이 글을 통해 여러분은 n8n 데이터 마스터로 거듭날 수 있을 거예요! 💪
1. n8n 데이터 변환의 핵심: JSON 이해하기 💡
n8n에서 모든 데이터는 기본적으로 JSON(JavaScript Object Notation) 형태로 흐릅니다. JSON은 데이터를 구조화하여 표현하는 데 사용되는 가볍고 읽기 쉬운 형식입니다. n8n 워크플로우의 각 노드는 JSON 데이터를 입력받아 처리하고, 또 다른 JSON 데이터를 출력합니다.
1.1 JSON 기본 구조와 접근 방법
JSON은 키(key)
와 값(value)
의 쌍으로 이루어져 있으며, 객체 {}
또는 배열 []
형태로 표현됩니다.
예시 JSON 데이터:
[
{
"id": 1,
"name": "김철수",
"email": "chulsoo@example.com",
"details": {
"age": 30,
"city": "서울"
},
"orders": [
{ "order_id": "A101", "amount": 50000 },
{ "order_id": "B202", "amount": 25000 }
]
},
{
"id": 2,
"name": "이영희",
"email": "younghee@example.com",
"details": {
"age": 25,
"city": "부산"
},
"orders": []
}
]
n8n에서는 표현식(Expressions)을 사용하여 JSON 데이터의 특정 값에 접근할 수 있습니다. 표현식은 중괄호 {{ }}
로 감싸서 사용합니다.
- 기본 값 접근:
{{ $json.name }}
- 위 예시에서 첫 번째 아이템의 “name” 값인 “김철수”에 접근합니다.
- 중첩된 값 접근:
{{ $json.details.city }}
- 첫 번째 아이템의 “city” 값인 “서울”에 접근합니다.
- 배열 내 특정 요소 접근:
{{ $json.orders[0].order_id }}
- 첫 번째 아이템의 “orders” 배열 중 첫 번째(인덱스 0) 객체의 “order_id” 값인 “A101″에 접근합니다.
- 동적 키 접근:
{{ $json['dynamic_key'] }}
- 키 이름이 변수에 저장되어 있을 때 유용합니다.
1.2 Set
노드를 활용한 JSON 데이터 생성 및 수정
Set
노드는 n8n에서 데이터를 조작하는 데 가장 많이 사용되는 노드 중 하나입니다. 새로운 필드를 추가하거나, 기존 필드의 값을 변경하거나, 복잡한 JSON 객체를 구성할 때 유용합니다.
예시: 사용자 정보에 “상태” 필드 추가 및 이메일 주소 변경
- 시나리오: API 응답으로 받은 사용자 정보에
status: "active"
필드를 추가하고,email
주소를 모두 소문자로 변경하고 싶을 때. - 노드:
Set
노드를 사용합니다. - 설정:
Value
필드:email
Expression
:{{ $json.email.toLowerCase() }}
Value
필드:status
Expression
:"active"
(문자열은 따옴표로 감싸야 합니다)
2. 배열(Array) 데이터 다루기: 반복과 조작 ⚙️
배열은 여러 개의 데이터를 순서대로 담는 리스트 형태의 데이터 구조입니다. API 응답에서 여러 개의 레코드를 받거나, DB에서 여러 행을 조회할 때 배열 형태로 데이터를 받게 됩니다.
2.1 배열 데이터를 개별 아이템으로 분리: Split Out Items
(구 Item Lists) 노드
가장 흔한 시나리오는 하나의 워크플로우 아이템에 배열 형태로 담겨 있는 여러 데이터를 각각의 개별 워크플로우 아이템으로 분리하여 처리하고 싶을 때입니다. 이 때 Split Out Items
노드를 사용합니다.
예시: 여러 주문 정보를 각각의 아이템으로 분리하여 처리
- 시나리오: 한 고객의 주문 내역이 배열
orders: []
안에 들어있고, 이 주문들을 각각의 아이템으로 분리하여 개별 주문에 대한 처리(예: 송장 생성, 재고 차감)를 진행하고 싶을 때. - 노드:
Split Out Items
- 설정:
Field To Split Out
:orders
(분리하고 싶은 배열의 키를 입력합니다)
- 결과:
orders
배열의 각 요소가 새로운 워크플로우 아이템으로 생성됩니다. 예를 들어,orders
배열에 2개의 주문이 있었다면, 2개의 독립적인 워크플로우 아이템이 다음 노드로 전달됩니다.
2.2 배열 데이터를 반복 처리: Loop Over Items
노드
Loop Over Items
노드는 Split Out Items
와는 조금 다릅니다. 이 노드는 각각의 아이템에 대해 동일한 일련의 노드를 반복 실행하고 싶을 때 사용합니다. 이는 서브-워크플로우처럼 작동하며, 반복이 끝난 후 모든 결과를 다시 합칠 수 있습니다.
예시: 각 주문 아이템에 대해 외부 API 호출
- 시나리오:
Split Out Items
로 분리된 각 주문 아이템에 대해, 주문 ID를 사용하여 외부 배송 API에 트래킹 정보를 요청하고 싶을 때. - 노드:
Loop Over Items
노드 뒤에HTTP Request
노드를 연결합니다. - 설정:
Loop Over Items
: 특정 설정 없이, 단순히 이 노드 안에 반복할 워크플로우를 넣으면 됩니다.HTTP Request
:URL
에{{ $json.order_id }}
와 같이 각 아이템의 데이터를 참조하여 요청을 보냅니다.
- 결과: 모든 주문 아이템에 대한 API 호출이 순차적으로(또는 병렬로) 실행되고, 각 호출의 결과가 다시 합쳐져
Loop Over Items
노드의 출력으로 나옵니다.
2.3 Code
노드를 활용한 고급 배열 조작 (JavaScript)
Code
노드는 n8n 워크플로우 내에서 JavaScript 코드를 실행하여 데이터를 자유자재로 다룰 수 있게 해줍니다. 배열 필터링, 매핑, 정렬, 그룹화 등 복잡한 배열 조작에 강력합니다.
예시 1: 배열 필터링 (특정 조건 만족하는 아이템만 남기기)
- 시나리오: 주문 배열에서
amount
가 30000원 이상인 주문만 필터링하고 싶을 때. -
코드:
// 입력 데이터의 각 아이템은 'item' 변수로 접근 가능하며, 전체 아이템은 'items' 배열로 접근 가능합니다. const filteredOrders = items.filter(item => item.json.amount >= 30000); return filteredOrders; // 필터링된 결과를 반환합니다.
예시 2: 배열 매핑 (배열의 각 아이템 변형)
- 시나리오: 주문 배열의 각 주문에 대해
order_id
와status: "processing"
필드만 남기고 싶을 때. -
코드:
const mappedOrders = items.map(item => ({ order_id: item.json.order_id, status: "processing" })); return mappedOrders;
예시 3: 배열 평탄화 (Nested Array Flattening)
- 시나리오: 고객 목록에서 각 고객의
orders
배열에 있는 모든 주문을 하나의 단일 배열로 합치고 싶을 때. -
코드:
const allOrders = items.flatMap(item => item.json.orders); return allOrders;
flatMap
은 배열을 매핑한 후, 결과 배열을 평탄화(flatten)하는 편리한 메서드입니다.
3. 루프(Loop)를 활용한 고급 시나리오 🔄
단순히 배열을 분리하는 것을 넘어, 특정 조건이 만족될 때까지 반복하거나, 페이지네이션이 적용된 API를 처리하는 등 다양한 고급 루프 시나리오를 n8n에서 구현할 수 있습니다.
3.1 Do While
루프 노드를 활용한 페이지네이션 처리
많은 API는 한 번에 모든 데이터를 반환하지 않고, 페이지 단위로 데이터를 제공합니다. 이럴 때 Do While
루프 노드를 사용하여 다음 페이지가 없을 때까지 반복적으로 데이터를 가져올 수 있습니다.
예시: 페이지네이션된 API에서 모든 데이터 가져오기
- 시나리오:
page
파라미터로 페이지 번호를 넘겨주면 데이터를 반환하는 API가 있습니다. 모든 페이지의 데이터를 가져와야 합니다. - 노드 구성:
Start
->Do While
Do While
내부:HTTP Request
(API 호출),Set
(다음 페이지 번호 업데이트 또는 종료 조건 확인)
Do While
이후:Merge
(모든 페이지 데이터 합치기)
Do While
설정:Mode
:Loop
(반복)Condition
:{{ $json.next_page_exists }}
(다음 페이지가 있는지 여부를 나타내는 플래그. API 응답에서 이 값을 가져와야 합니다.)Initial Value
:page=1
(첫 번째 페이지 시작)Increment Value
:page = page + 1
(매 루프마다 페이지 번호 증가)
HTTP Request
및 Set
노드 로직 (Do While 내부):
HTTP Request
:URL
에page
파라미터를{{ $json.page }}
와 같이 동적으로 넣어줍니다.Set
노드:- API 응답에서 다음 페이지가 있는지 여부를 확인하는 로직 (예:
data.length > 0
또는response.has_more
)을next_page_exists
라는 새로운 필드에 저장합니다. page
변수를 1 증가시킵니다:{{ $json.page + 1 }}
- API 응답에서 다음 페이지가 있는지 여부를 확인하는 로직 (예:
3.2 Code
노드를 활용한 커스텀 루프 및 조건부 처리
Do While
노드 외에도, Code
노드 안에서 직접 JavaScript의 for
루프나 while
루프를 사용하여 훨씬 유연한 반복 로직을 구현할 수 있습니다.
예시: 특정 작업 N번 반복 및 상태 업데이트
- 시나리오: 특정 API를 5번 호출하거나, 특정 조건이 충족될 때까지 일정한 간격으로 작업을 반복하고 싶을 때.
-
코드 (간단한 N회 반복):
const results = []; for (let i = 0; i t.amount >= 200) }}
* **설명:** 현재 아이템의 `transactions` 배열에 대해 `filter` 메서드를 적용합니다. 각 트랜잭션 `t`의 `amount`가 200 이상인 경우에만 새 배열에 포함시킵니다.
- 결과 확인:
high_value_transactions
필드에 필터링된 트랜잭션 배열이 포함됩니다.
- 결과 확인:
4.2 예제 2: 여러 API 응답 병합 및 고유 값 추출 🔗
-
시나리오: 서로 다른 두 개의 API(예:
active_users
와inactive_users
)에서 사용자 목록을 가져와서 하나의 통합된 사용자 목록으로 합치고, 중복되는 사용자를 제거하여 고유한 사용자만 남기고 싶습니다. -
워크플로우 노드 구성:
HTTP Request (Active Users)
: 활성 사용자 API 호출HTTP Request (Inactive Users)
: 비활성 사용자 API 호출Merge
노드: 두 API 응답을 병합합니다.- Mode:
Merge By Index
또는Merge By Property
(여기서는 단순히 모든 데이터를 합치므로Append
도 가능) - 설정: 두
HTTP Request
노드의 출력을 이 노드의 입력으로 연결합니다.
- Mode:
-
Code
노드: 병합된 사용자 목록에서 중복을 제거합니다.-
Code:
const users = items.map(item => item.json); // 모든 사용자 아이템을 순수 JSON 객체 배열로 변환 const uniqueUsers = Array.from(new Map(users.map(user => [user.email, user])).values()); // 'email'을 기준으로 중복을 제거합니다. Map 객체는 키의 고유성을 활용합니다. // 마지막으로 'values()'로 Map의 값들만 추출하여 배열로 만듭니다. return uniqueUsers; // 고유한 사용자 목록 반환
- 주의:
user.email
은 중복 여부를 판단할 고유 키로, 실제 데이터에 따라user.id
등으로 변경할 수 있습니다.
- 주의:
-
- 결과 확인: 중복이 제거된 통합된 사용자 목록을 얻게 됩니다.
4.3 예제 3: 재고 알림 시스템 (조건부 루프 및 데이터 변형) 🚨
-
시나리오: 주기적으로 제품 재고를 확인하는 API를 호출하고, 특정 제품의 재고가 10개 미만으로 떨어지면 Slack으로 알림을 보내고, 알림 발송 후에는 해당 제품의 재고를 업데이트(로깅)하는 워크플로우를 만들고 싶습니다.
-
워크플로우 노드 구성:
Cron
: 매일 특정 시간에 워크플로우 실행HTTP Request (Get Inventory)
: 제품 재고 API 호출- 응답 데이터 예시:
[ { "product_id": "P001", "name": "스마트폰", "stock": 15 }, { "product_id": "P002", "name": "노트북", "stock": 5 }, { "product_id": "P003", "name": "태블릿", "stock": 20 } ]
- 응답 데이터 예시:
Split Out Items
: 각 제품을 개별 워크플로우 아이템으로 분리- Field To Split Out:
json
(API 응답이 바로 배열이므로, 전체json
객체를 분리)
- Field To Split Out:
If
노드: 재고 조건 확인- Value 1:
{{ $json.stock }}
- Operation:
Less Than Or Equal
(<=
) - Value 2:
10
- Value 1:
If
노드의True
분기 (재고 부족 시):Set
노드: Slack 메시지 내용 생성- Value:
message
- Expression:
재고 부족 알림: 제품 "{{ $json.name }}" (ID: {{ $json.product_id }})의 재고가 {{ $json.stock }}개 남았습니다.
- Value:
Slack
노드: Slack으로 알림 전송- Text:
{{ $json.message }}
- Text:
If
노드의False
분기 (재고 충분 시):No Op
: 아무것도 하지 않고 다음으로 진행
Code
노드: 재고 업데이트 로깅 (모든 제품에 대해 실행)- Code:
// 이 예시에서는 단순히 콘솔 로그를 남기지만, 실제로는 DB 업데이트 API 호출 등을 할 수 있습니다. console.log(`제품 ${items[0].json.name} (ID: ${items[0].json.product_id})의 현재 재고: ${items[0].json.stock}`); return items; // 원래 아이템을 그대로 반환
- 참고:
Split Out Items
로 분리된 각 제품 아이템이 이Code
노드로 들어오므로,items[0]
대신item
을 직접 참조하여 현재 제품 정보를 활용할 수 있습니다. (정확히는items
배열에는 해당Split Out Items
로 생성된 단일 아이템이 들어있습니다.item
변수는Function
노드에서 사용됩니다.)Code
노드에서는item
보다는items[0]
이 더 명확합니다.
- 참고:
- Code:
5. 꿀팁 & 베스트 프랙티스 ✨
- 데이터 흐름 시각화: 워크플로우 실행 후, 각 노드의 출력 데이터를 확인하여 데이터가 어떻게 변환되고 있는지 항상 확인하세요. n8n의 “실행 기록(Executions)” 탭은 이 과정에서 매우 유용합니다.
Set
노드 적극 활용:Set
노드는 데이터의 구조를 변경하고, 필요한 정보를 조합하거나 삭제하는 데 있어 만능 키입니다. 작은 변환이라도Set
노드를 사용하여 명확하게 처리하는 것이 좋습니다.Code
노드는 최후의 수단:Code
노드는 강력하지만, 디버깅이 어렵고 복잡해질 수 있습니다. 가능하다면 내장된 노드(Set, Split Out Items, If, Merge 등)를 먼저 고려하고, 정말 필요한 경우에만Code
노드를 사용하세요.- 테스트 데이터 사용: 실제 데이터 대신 작은 규모의 테스트 데이터를 사용하여 워크플로우를 개발하고 디버깅하는 것이 효율적입니다.
Static Data
노드나 간단한Function
노드로 테스트 데이터를 생성할 수 있습니다. - 주석(Notes) 활용: 복잡한 로직이나 중요한 데이터 변환 노드에는 주석을 달아 나중에 워크플로우를 이해하고 유지보수하기 쉽게 만드세요.
- 에러 처리:
Try/Catch
노드를 사용하여 예상치 못한 에러에 대비하고, 에러 발생 시 알림을 보내거나 재시도하는 로직을 추가하는 것이 좋습니다.
마무리하며 🌟
n8n에서 JSON, 배열, 그리고 루프를 마스터하는 것은 복잡한 자동화 워크플로우를 구축하는 데 필수적인 능력입니다. 이 글에서 다룬 개념과 예시들을 꾸준히 연습하고 여러분의 워크플로우에 적용해보세요.
처음에는 어려울 수 있지만, 반복적인 학습과 실습을 통해 n8n 데이터 변환의 진정한 힘을 경험하게 될 것입니다. 이제 n8n으로 더욱 강력하고 효율적인 자동화를 만들어낼 준비가 되셨습니다! 궁금한 점이 있다면 언제든지 댓글로 남겨주세요. 행복한 자동화 생활 되세요! 😊 D