Hoàn thành bài "Bài học 3: Logic điều kiện với các nút IF và Switch" trước để mở khoá bài này.Đến bài trước

Giới thiệu

Code node là một trong những công cụ mạnh nhất của n8n. Khi các nút tích hợp sẵn như Set, Edit Fields hoặc Split Out không thể thực hiện đúng những gì bạn cần, Code node cho phép bạn viết JavaScript thực sự để biến đổi dữ liệu EXACTLY theo ý bạn muốn. Nó chạy trong môi trường Node.js được cách ly và có quyền truy cập trực tiếp vào cấu trúc mục của n8n, cho bạn toàn quyền kiểm soát dữ liệu của workflow.

Bài học này tập trung vào ba trường hợp sử dụng thực tế: thao tác mảng, định dạng chuỗi và tính toán các trường mới từ các trường sẵn có.

Cách Code Node hoạt động

Code node vận hành trên mảng items được luồng qua workflow của bạn. Mỗi mục có một đối tượng gọi là json chứa dữ liệu của nó. Khi bạn mở Code node, bạn viết thân hàm — n8n bọc nó một cách tự động, nên bạn không cần tự xác định một hàm.

Có hai chế độ thực thi. "Run Once for All Items" cho bạn quyền truy cập vào tất cả các mục cùng một lúc thông qua biến items. "Run Once for Each Item" cung cấp cho bạn một biến mục đơn lẻ. Chế độ mặc định và linh hoạt nhất là "Run Once for All Items", đây là điều bài học này tập trung vào.

Trong chế độ này, mã của bạn phải trả về một mảng các đối tượng có hình dạng như sau:

javascript
return [
{ json: { fieldName: value } },
{ json: { fieldName: value } }
];

Mỗi đối tượng trong mảng trả về sẽ trở thành một mục đầu ra. Nếu bạn trả về một mảng rỗng, sẽ không có mục nào được truyền tiếp.

flowchart cho thấy mảng items đi vào Code node, logic JavaScript được áp dụng, mảng items đã biến đổi ra ngoài

Xử lý Mảng

Giả sử một nút upstream trả cho bạn một danh sách các đơn hàng, và mỗi mục có trường products là một mảng các đối tượng. Bạn muốn làm phẳng danh sách để mỗi sản phẩm trở thành một mục riêng biệt.

javascript
const result = [];
for (const item of items) {
const orderId = item.json.orderId;
const products = item.json.products;
for (const product of products) {
result.push({
json: {
orderId,
productName: product.name,
quantity: product.qty,
}
});
}
}
return result;

Nếu bạn bắt đầu với 3 mục đơn hàng, mỗi mục chứa 4 sản phẩm, bạn sẽ có 12 mục đầu ra. Đây là điều Split Out có thể làm được cho các trường hợp đơn giản, nhưng nút Code cho phép bạn mang theo ngữ cảnh đã tính toán từ mục cha cùng lúc.

Để làm ngược lại — gộp nhiều mục thành một — bạn có thể dùng reduce:

javascript
const grouped = items.reduce((acc, item) => {
const key = item.json.category;
if (!acc[key]) acc[key] = [];
acc[key].push(item.json.productName);
return acc;
}, {});
return Object.entries(grouped).map(([category, products]) => ({
json: { category, products }
}));

Định dạng chuỗi

Các biến đổi chuỗi là một lý do phổ biến để dùng nút Code. Trình chỉnh Expression xử lý các trường hợp đơn giản, nhưng định dạng nhiều bước thì gọn hơn trong mã.

Dưới đây là một ví dụ chuẩn hóa trường tên — bỏ đi khoảng trắng ở đầu/cuối, chuyển sang chữ hoa chữ thường ở dạng tiêu đề, và xây dựng nhãn hiển thị:

javascript
function toTitleCase(str) {
return str
.trim()
.toLowerCase()
.replace(/\b\w/g, (char) => char.toUpperCase());
}
return items.map((item) => {
const raw = item.json.fullName || '';
const formatted = toTitleCase(raw);
const initials = formatted
.split(' ')
.map((w) => w[0])
.join('');
return {
json: {
...item.json,
fullName: formatted,
initials,
displayLabel: `${formatted} (${initials})`,
}
};
});

Sử dụng toán tử trải rộng ...item.json giữ nguyên tất cả các trường hiện có và thêm các trường mới ở phía trên chúng, do đó các nút ở phía sau vẫn nhìn thấy dữ liệu ban đầu.

Tạo Trường Mới

Nút Code lý tưởng khi một trường mới phụ thuộc vào tính toán từ nhiều trường hiện có — các thứ như tổng, tuổi từ ngày sinh, hoặc các cờ trạng thái dựa trên quy tắc kinh doanh.

javascript
return items.map((item) => {
const { unitPrice, quantity, discountPercent } = item.json;
const subtotal = unitPrice * quantity;
const discountAmount = subtotal * (discountPercent / 100);
const total = subtotal - discountAmount;
const status =
total > 1000 ? 'high_value'
: total > 200 ? 'standard'
: 'low_value';
return {
json: {
...item.json,
subtotal: +subtotal.toFixed(2),
discountAmount: +discountAmount.toFixed(2),
total: +total.toFixed(2),
status,
}
};
});

Lưu ý việc sử dụng +value.toFixed(2) — toFixed trả về chuỗi, nên toán hạng đơn vị + chuyển nó trở lại thành số. Điều này quan trọng vì các nút phía sau thực hiện toán học hoặc so sánh sẽ hành xử khác nhau với chuỗi so với số.

đồ thị minh họa các trường mục đầu vào (unitPrice, quantity, discountPercent) chảy vào logic nút Code, tạo ra các trường đầu ra tính được (subtotal, discountAmount, total, status)

Những sai lầm phổ biến

Quên đóng gói đầu ra trong json là lỗi phổ biến nhất. Trả về { name: 'Alice' } thay vì { json: { name: 'Alice' } } sẽ khiến n8n báo lỗi hoặc bỏ qua dữ liệu một cách im lặng.

Mutating item.json directly instead of spreading it can cause unexpected side effects in some n8n versions — always build a new object.

Sử dụng await mà không đánh dấu Node Code là có thể async-capable: nếu bạn cần gọi helper tích hợp như $node hoặc dùng các thao tác bất đồng bộ, hãy đảm bảo logic của bạn xem xét chế độ thực thi. Các biến đổi đồng bộ tiêu chuẩn như các ví dụ ở trên không cần bất kỳ thiết lập đặc biệt nào.

Cuối cùng, Code node về cơ bản không có quyền truy cập vào các gói npm bên ngoài theo mặc định trên n8n Cloud. Trên n8n tự host, bạn có thể cho phéplist các gói, nhưng hãy viết code của bạn để có tính di động trừ khi bạn kiểm soát triển khai.

Tóm tắt

Code node cung cấp cho bạn một môi trường JavaScript đầy đủ để xử lý các biến đổi mà các nút tích hợp không diễn đạt một cách sạch sẽ. Thói quen chính là luôn trả về một mảng các đối tượng { json: ... }, phân tán các trường có sẵn khi bạn chỉ muốn thêm trường mới, và chọn "Run Once for All Items" khi biến đổi liên quan đến việc reshape collection chính.

Luyện tập sau buổi học

Bài kiểm tra cuối bài

Ôn lại kiến thức, thử sức và nhận góp ý cho bài làm.

0/1
Đã trả lời · 0/1