สอนใช้ n8n EP07 : วิธีดึงข้อมูลจาก Node ใน Workflow ที่ซับซ้อน 1

🗂️ Categories :

,

สอนใช้ n8n EP07 : วิธีดึงข้อมูลจาก Node ใน Workflow ที่ซับซ้อน

ในการสร้าง Workflow ด้วย n8n ที่ซับซ้อนขึ้นเรื่อย ๆ เราจะเจอเคสที่มีหลายเส้นทางข้อมูลวิ่งมา บางเส้นทางอาจรันเสมอ บางเส้นอาจถูกรันเฉพาะบางเงื่อนไข หรือ บางสถานการณ์เท่านั้น บางทีมันเป็นแค่ “ตัวเลือก” ว่าจะรันหรือไม่รันก็ได้…

ปัญหาคือ… ถ้าเราอยากดึงค่าจาก Node เหล่านั้นมาใช้ต่อ
แล้วบาง Node ยังไม่ได้ถูกรัน (Executed) → มันจะพังเอาได้ง่าย ๆ ❌

บทความนี้เลยอยากพามาดู “แนวทางที่ปลอดภัยและยืดหยุ่น” ว่าเราจะเขียน Expression ยังไงให้ ให้ดึงข้อมูลได้แบบไม่พัง ซึ่งถ้าเข้าใจหลักการพวกนี้แล้ว จะทำให้เราสร้าง Workflow ที่ซับซ้อนแค่ไหนก็รอดได้แน่นอนครับ!

โดยผมจะพายกตัวอย่าง ปัญหาที่เกิดได้บ่อยในเคสจริง ในการทำ Automation Workflow โดยเน้น “แนวทางปฏิบัติ” และตัวอย่างให้เห็นภาพครับ

1. เมื่อมี “หลายเส้น” ข้อมูลมารวมกัน: ใช้ Merge Node

นี่เป็นปัญหาคลาสสิกของคนทำ Automation เลย เวลา Data หลายสาย (เช่นจากหลาย หลาย Data Source) วิ่งมาทั้งสองเส้น Merge Node คือเครื่องมือหลักที่ต้องรู้จัก! เพราะมันจะสามารถรวมข้อมูลจากหลายเส้นทางเข้าด้วยกันได้ พอรวมได้แล้ว การอ้างอิงก็ทำได้ง่ายเลย เพราะว่าก็เหมือนกลับมามีเส้นทางเดียวตามปกตินั่นเอง

เช่น เรามี Workflow แบบนี้

สอนใช้ n8n EP07 : วิธีดึงข้อมูลจาก Node ใน Workflow ที่ซับซ้อน 2

ตัวบน เป็น data mockup ของ n8n เอง คือ Customer Datastore ที่มีลูกค้า 5 คน แต่ละคนมาจากประเทศที่แตกต่างกันไป (มีซ้ำบ้าง ว่างบ้าง)

ตัวล่างเป็น edit field ที่ผม edit output ไว้แบบ manual เลยแบบนี้ ว่าแต่ละประเทศอยู่ในทวีปไหน?

[
  {
    "country": "US",
    "continent": "North America"
  },
  {
    "country": "UK",
    "continent": "Europe"
  },
  {
    "country": "TH",
    "continent": "Asia"
  }
]

Merge Node ทำงานได้หลายโหมดนะ

ถ้าเราจะเอา Data มารวมกัน เราจะใช้ Merge Node มาช่วย ซึ่งทำได้หลายแบบมากๆ มาดูกันทีละแบบเลยว่าทำงานยังไง

Append

เอา data 2 อันมาต่อแถวกัน (5+3 = 8 items) โดยเอาชื่อ fields เหมือนกันต่อกัน

ซึ่งคงไม่ใช่แบบที่เราอยากได้แน่ๆ สำหรับ Data ในเคสนี้ แต่ถ้าเอาการเอา data 2 อัน เช่น ลูกค้า 2 ตาราง มาต่อรวมกัน อันนี้จะ Make Sense ทันที

หมายเหตุ : การ Append จะสามารถเลือก data ได้ สูงสุดทีละ 10 inputs (10 ตาราง)

Combine

ตัวนี้ก็มีหลายแบบมากๆ เช่น

Combine By แบบ Matching Fields

ถ้าใช้ Combine By แบบ Matching Fields เบื้องหลังมันจะทำแบบ SQL Join ซึ่งตัวที่ผมใช้บ่อย เพราะคล้ายๆ VLOOKUP ใน Excel คือ Enrich Input1 (Left Join) ซึ่งจะได้ Input1 ครบทุกตัว และได้ Field จาก input 2 มาเพิ่ม เท่าที่จะเจอ สำหรับ Join แบบอื่นๆ ลองไปเล่นเอาเองนะ แค่กดดูก็พอจะเข้าใจแล้วล่ะ

หมายเหตุ : การ Combine By แบบ Matching Fields จะสามารถเลือก data ได้ สูงสุดทีละ 2 inputs (2 ตาราง) ถ้าอยากได้มากกว่านี้ให้ไปเลือกแบบ SQL Query

Combine By แบบ Position

ถ้าใช้ Combine By แบบ Position มันจะเอา item ที่ลำดับตรงกันชนกัน โดยไม่ได้ยึดจากค่าใน Field เลย (คล้ายๆ HSTACK ใน Excel ที่เอาคอลัมน์มาต่อกันในแนวนอน) โดยที่สามารถเลือก option ให้ Include unpaired item ได้ด้วย

อย่างไรก็ตาม ถ้ามันมีชื่อ Field ซ้ำกัน มันจะเอา Data ทับเลย สังเกตว่า country ของ 3 คนแรกมันถูกแก้จนมั่วไปแล้ว 😱

ดังนั้น ถ้าจะใช้วิธีนี้คือต้องมั่นใจว่า item1 ควรชนกับ item1, item2 ควรชนกับ item2… จนครบ ไม่งั้นไม่ work นะ

หมายเหตุ : การ Combine By แบบ Position จะสามารถเลือก data ได้ สูงสุดทีละ 10 inputs (10 ตาราง)

Combine By แบบ All Possible Combinations

แบบนี้คือจะคล้ายกับ By Position แต่มันเอา Data ทุกตัวของตาราง 2 มาเบิ้ลลงแต่ละ item ของตารางแรกไปเลย ดังนั้นจะออกมา = 5*3 = 15 items

จะเห็นว่าชื่อ field ถ้าซ้ำ มันก็จะทับ data ไปเลยเช่นกัน อย่าง Jay Gatsby กลายเป็นอยู่ทั้ง 3 ประเทศไปเลย 😂

SQL Query

ถ้าเราใช้โหมดนี้ เราจะสามารถเขียน SQL ได้เองตามใจชอบ ซึ่งจะมีความยืดหยุ่นสูง และรองรับได้ถึง 10 inputs เลย (แปลว่าถ้าไม่อยาก Combine หลายรอบ ก็มาใช้ตัวนี้ได้)

ซึ่งถ้าเราเขียน SQL เองไม่เป็น ก็ให้ AI ช่วยเขียนได้อยู่แล้วเนอะ ❤️

Choose Branch

ตัวนี้มีหน้าที่ในการ รอ ให้ input ทุกตัวถูกรันจนครบก่อน แล้วค่อยส่งค่าจาก input ซักตัวนึงได้วิ่งต่อไป ซึ่งมีประโยชน์ในบางกรณี เพราะถ้าเราไม่มีตัวนี้ โปรแกรมจะพยายามรันเส้นบนสุดจนครบก่อนทั้งเส้น แล้วค่อยรันเส้นล่างต่อ ซึ่งกลายเป็นว่า ข้อมูลบางอย่างที่เราต้องใช้มันยังไม่ถูกรัน (บางทีเราต้องการรัน แต่ยังไม่ได้ใช้ต่อตรงๆ)

2. เมื่อมีเส้นทางที่มาได้หลายเส้น แต่ข้อมูลวิ่งมาแค่เส้นใดเส้นหนึ่ง

ก่อนจะอธิบายถึง case ปัญหานี้ เรามาทำความรู้จัก Operator ที่สำคัญ 2 ตัว นี้ก่อน

  • ?? คือ Coalesce Operator : เอาไว้เอาค่าที่ไม่ว่าง อันแรก
    • เอาค่าแรกที่ “ไม่เป็น null หรือ undefined”
    • เหมาะกับข้อมูลที่ 0, false, ” ยังถือว่า “มีค่า”
  • || คือ OR Operator : เอาค่าที่ดูเหมือนเป็นจริง อันแรก (เอาค่าแรกที่ “truthy”)
    • ค่าที่ไม่ใช่ 0, ไม่ใช่ ”, ไม่ใช่ false, ไม่ใช่ null, ไม่ใช่ undefined
    • ค่าที่เป็น 0, ” หรือ false จะโดนมองข้ามหมด

ยกตัวอย่างให้เข้าใจง่ายๆ สมมติผมมี Workflow หน้าตานี้

สอนใช้ n8n EP07 : วิธีดึงข้อมูลจาก Node ใน Workflow ที่ซับซ้อน 11

โดยที่ edit field อันแรก เป็นการเตรียม field Y ให้มีค่าเป็น 0 เฉยๆ เลย

แล้ว 2 โหนดหลัง ลองใช้ Operator ที่ต่างกัน ดังนี้

{{ $json.X??$json.Y??777 }}

อันนี้ผลลัพธ์จะได้ 0 เพราะ X ไม่มี ไปดู Y แล้ว Y เป็น 0 ถือว่าไม่ว่าง จบเลย

{{ $json.X||$json.Y||777 }}

อันนี้ผลลัพธ์จะได้ 777 เพราะ X ไม่มี ไปดู Y แล้ว Y เป็น 0 ถือว่าไม่จริง เลยไปเอา 777 แทน (ตัวที่ถือว่าไม่จริง เช่น false, 0, '' (สตริงว่าง), null, undefined )

ลองใช้ Operator ในการเลือกค่าจากเส้นที่วิ่งมาเส้นใดเส้นหนึ่ง

วิธีนี้จะ work ก็ต่อเมื่อ มีการอ้างอิงจาก node ก่อนหน้าการเขียนสูตรทันทีเท่านั้น ซึ่งเราอ้างอิงด้วย $json (ที่แปลว่า json จาก node ก่อนหน้า)

สอนใช้ n8n EP07 : วิธีดึงข้อมูลจาก Node ใน Workflow ที่ซับซ้อน 15

เช่น ถ้า Field ชื่อ MyVarFinal เขียนสูตรไว้แบบนี้

{{ $json.MyVar1??$json.MyVar2??777 }}

เช็คว่า MyVar1 มีไหม? ถ้าไม่มีก็เอา MyVar2 แต่ถ้าไม่มีอีก ก็เอา 777 ไล่ตามลำดับไป

  • ถ้า Run จาก Trigger1 : จะได้ MyVarFinal เป็น 777 เพราะ
    • MyVar1 ไม่มี (เพราะไม่ได้ตั้งค่าตัวแปรไว้)
    • MyVar2 ไม่มี (เพราะไม่ได้รันเส้นนั้น)
    • ทำให้ไปได้ค่า 777 (ค่า default ตัวสุดท้าย) มาตอบ
  • ถ้า Run จาก Trigger2 : จะได้ MyVarFinal เป็น 0 เพราะ
    • MyVar1 ไม่มี (เพราะไม่ได้ตั้งค่าตัวแปรไว้)
    • MyVar2 มีค่า 0
    • ทำให้ไปได้ค่า 0 มาตอบ (ค่าจาก MyVar2) ไปไม่ถึงตัวสุดท้าย

ถ้า Node หรือตัวแปรที่อ้างอิง ยังไม่ได้ถูกสร้างขึ้นมาเลยตั้งแต่แรก

มันจะมีกรณีที่เรามีการอ้างอิง Node แบบเจาะจงไปเลย (โดยไม่ได้ใช้การอ้างอิง $json เพื่อหมายถึง “Node ก่อนหน้า” ) ซึ่งถ้า Node ที่เราอ้างอิงนั้นไม่มีอยู่จริง (เพราะไม่ได้ถูกรัน) การใช้ ?? หรือ || จะไม่ Work ทันที เช่นแบบนี้

{{ $('Schedule Trigger1').item.json.MyVar1??$('MyVar2').item.json.MyVar2??777 }}

แบบนี้คือมีการอ้างอิง MyVar1 ใน Node ชื่อ Schedule Trigger1 ซึ่งถ้าเรารัน Trigger ด้านบน มันจะบอกว่า Referenced node is unexecuted (node ‘MyVar2’)

แต่ถ้าเรารัน Trigger ล่าง มันก็จะบอกตรงข้ามกันว่า Schedule Trigger1 ไม่ได้ถูก executed…

ทางแก้อันนึงคือใช้การเช็คว่า Node ที่สนใจถูก Executed รึเปล่า? ด้วยการเช็คแบบนี้

{{ $('Schedule Trigger1').isExecuted }}

ซึ่งมันจะได้ออกมาเป็น true ไม่ก็ false

จากนั้นเราเอาไปใช้ใน if อีกทีนึงได้ เช่น

{{ $if( $('Schedule Trigger1').isExecuted , 
$('Schedule Trigger1').item.json.MyVar1,
$('MyVar2').item.json.MyVar2 )}}

ผลลัพธ์จะถูกดึงมาได้ (แต่ต้องกด run workflow ตั้งแต่ trigger เลย ถึงจะเห็นค่า ถ้าไปกด Test Step จากใน edit field มันจะยังบอกว่า error อยู่ ซึ่งเป็น bug)

แน่นอนว่าเราผสมกับ || ได้อีก เช่น

{{ $if( $('Schedule Trigger1').isExecuted , 
$('Schedule Trigger1').item.json.MyVar1,
$('MyVar2').item.json.MyVar2||777 )}}

แบบนี้ถ้า Run Trigger2 ก็จะได้ 777 นั่นเอง

⭐️ สรุป

การดึงข้อมูลจากหลายเส้นทางใน Workflow ที่ซับซ้อน ไม่ใช่แค่เรื่องของ “รวมข้อมูล” แต่คือเรื่องของ “ความเข้าใจในลำดับการทำงาน” และ “การป้องกัน error จาก Node ที่ยังไม่ถูก execute”

เทคนิคสำคัญที่ควรรู้และใช้ให้คล่อง:

  • ใช้ ?? เมื่อเราต้องการ “ค่าที่ไม่เป็น null/undefined”
  • ใช้ || เมื่อเราต้องการ “ค่าที่ truthy” เท่านั้น (ระวัง 0 หรือ false ถูกมองข้าม)
  • ใช้ .isExecuted เช็กให้ชัวร์ว่า Node นั้นรันแล้ว ก่อนจะอ้างอิงค่า

การเข้าใจหลักการพวกนี้ จะช่วยให้เราสามารถเขียน Workflow ที่รองรับหลายสถานการณ์ได้อย่างยืดหยุ่น ปลอดภัย และดูโปรขึ้นอีกเยอะ

หวังว่าบทความนี้จะช่วยให้เพื่อนๆ ที่ทำ Automation Workflow ด้วย n8n เข้าใจภาพรวมของ “การจัดการข้อมูลจากหลาย Node” ได้ดีขึ้นนะครับ 🔥

Leave a Reply

Your email address will not be published. Required fields are marked *