Supabase Postgres Changes กรองหลายเงื่อนไขได้ตั้งแต่ต้นทาง แถวที่ไม่เกี่ยวจึงไม่มาถึงแอป
Postgres Changes ต่อเงื่อนไขกรองหลายคอลัมน์ด้วยคอมมาได้แล้ว พร้อมตัวดำเนินการใหม่ และตัวเลือก select สำหรับรับเฉพาะคอลัมน์ที่หน้าจอใช้ จึงลบโค้ดกรองซ้ำใน callback ได้ พร้อมลดทั้งจำนวน message และปริมาณข้อมูลที่ Realtime ใช้คิดเงิน

Postgres Changes ใช้สมัครฟังตอนมีการเพิ่ม แก้ไข หรือลบแถวในตาราง Postgres แล้วส่งเหตุการณ์ผ่าน WebSocket มาทันที คนทำแชต แดชบอร์ดสด และระบบแจ้งเตือนบน Supabase คุ้นกับท่านี้กันดี แต่ก่อนตัวกรองมองได้ทีละคอลัมน์ จึงต้องสมัครฟังเผื่อไว้กว้างๆ แล้วค่อยเขียนเงื่อนไขที่เหลือใน callback เพื่อทิ้งแถวที่ไม่เกี่ยวเมื่อข้อมูลมาถึงแอป
รอบนี้ Supabase เพิ่มความสามารถมาพร้อมกันสามอย่าง ได้แก่ ต่อเงื่อนไขกรองข้ามหลายคอลัมน์ ใช้ตัวดำเนินการได้มากขึ้น และเลือกว่าจะรับคอลัมน์ไหนกลับมาบ้าง ทั้งสามอย่างใช้ได้แล้ว และช่วยย้ายงานที่เคยต้องกรองในแอปไปทำที่ต้นทาง แถวที่ไม่เกี่ยวจึงไม่ถูกส่งออกจากฐานข้อมูลตั้งแต่แรก
ต่อเงื่อนไขด้วยคอมมา ทุกข้อต้องเป็นจริงพร้อมกัน
เห็นภาพได้ง่ายๆ จากหน้ารวมตั๋วของทีมซัพพอร์ต หน้าจอนี้ต้องแสดงเฉพาะตั๋วที่ยังเปิดอยู่และเป็นของทีมตัวเอง จึงต้องใช้สองเงื่อนไขพร้อมกัน แต่ก่อนตัวกรองเลือกได้อย่างเดียวว่าจะดูสถานะหรือดูทีม จะใช้ทั้งคู่ไม่ได้ จึงต้องสมัครฟังตั๋วที่เปิดอยู่ทั้งตาราง แล้วค่อยทิ้งตั๋วของทีมอื่นเมื่อข้อมูลมาถึงแอป
ตอนนี้ต่อเงื่อนไขโดยคั่นด้วยคอมมาได้เลย โดยจะได้รับเหตุการณ์ก็ต่อเมื่อทุกเงื่อนไขเป็นจริงพร้อมกัน
supabase
.channel('team-inbox')
.on(
'postgres_changes',
{
event: 'UPDATE',
schema: 'public',
table: 'tickets',
filter: 'status=eq.open,team=eq.billing',
},
(payload) => console.log(payload)
)
.subscribe()
เงื่อนไขที่คั่นด้วยคอมมาจะรวมกันแบบ AND เสมอ ดังนั้น if ที่เคยใช้กรองทีมซ้ำใน callback จึงลบได้ทั้งท่อน เพราะตั๋วของทีมอื่นจะไม่วิ่งมาถึง callback แล้ว
ตัวดำเนินการชุดใหม่ ทำให้กรองได้มากกว่าแค่ค่าเท่ากัน
เงื่อนไขที่หน้าจอใช้จริงส่วนใหญ่ไม่ได้มีแค่การเช็กว่าค่าตรงกันเป๊ะ รอบนี้จึงมีตัวดำเนินการเพิ่มมาอีกชุด
| ตัวดำเนินการ | ใช้ตอนไหน | ตัวอย่าง |
|---|---|---|
like / ilike | จับรูปแบบข้อความ โดยเลือกได้ว่าจะสนใจตัวพิมพ์ใหญ่เล็กหรือไม่ | email=like.%@example.com |
is | เช็ก null และค่าจริงเท็จ | deleted_at=is.null |
match / imatch | เทียบด้วยรูปแบบ POSIX regular expression | slug=match.^post- |
isdistinct | เทียบว่าไม่เท่ากันโดยนับ null ด้วย | state=isdistinct.active |
isdistinct ต่างจาก neq ตรงที่มันนับ null เป็นค่าที่ใช้เทียบได้ ถ้าคอลัมน์นั้นเป็น null แถวดังกล่าวจึงถือว่าต่างจากค่าที่ระบุและผ่านตัวกรองเข้ามา ส่วนตัวดำเนินการทุกตัวกลับเงื่อนไขได้ด้วยการเติม not. ไว้ข้างหน้า เช่น status=not.eq.archived ซึ่งหมายถึงเอาทุกสถานะยกเว้นสถานะที่เก็บเข้ากรุแล้ว
ถ้าไม่อยากต่อสตริงเอง มีตัวช่วยประกอบเงื่อนไขในโค้ดให้
import { postgresChangesFilter } from '@supabase/supabase-js'
filter: postgresChangesFilter().eq('status', 'open').gte('priority', 3)
เงื่อนไขที่ต่อด้วยตัวช่วยจะรวมกันแบบ AND เหมือนการคั่นด้วยคอมมา และถ้าค่ามีอักขระที่ระบบจองไว้ เช่น , ( ) " และ \ ตัวช่วยจะใส่เครื่องหมายคำพูดให้เอง แต่ถ้าประกอบสตริงเอง ต้องครอบค่านั้นด้วยเครื่องหมายคำพูดคู่ เช่น name=eq."Doe, Jane" ไม่อย่างนั้นเซิร์ฟเวอร์จะตีความคอมมาในชื่อคนว่าเป็นตัวคั่นเงื่อนไข
select กำหนดว่าจะส่งคอลัมน์ไหนมาในแถว

ตัวกรองเอาไว้กำหนดว่าจะรับแถวไหน ส่วนการเลือกคอลัมน์กำหนดว่าแต่ละแถวจะส่งข้อมูลอะไรมา สองอย่างนี้ทำหน้าที่คนละส่วนกัน แต่ก่อนทุกเหตุการณ์จะขนข้อมูลมาทั้งแถว ทั้งเนื้อตั๋วยาวๆ และข้อมูลประกอบอีกกอง แม้หน้าจอจะเรนเดอร์แค่หัวเรื่องบรรทัดเดียวก็ตาม เมื่อใส่ตัวเลือก select ลงในคอนฟิกก้อนเดียวกับ event schema และ table payload ก็จะเหลือเฉพาะคอลัมน์ที่ระบุไว้
supabase
.channel('team-inbox')
.on(
'postgres_changes',
{
event: '*',
schema: 'public',
table: 'tickets',
select: ['id', 'subject', 'updated_at'],
},
(payload) => console.log(payload)
)
.subscribe()
คีย์หลักของตารางจะถูกส่งมาเสมอ แม้ไม่ได้ใส่ไว้ในลิสต์ ฝั่งที่รับจึงยังรู้ว่าแถวไหนเปลี่ยน ฟีเจอร์นี้ต้องเลือกเปิดใช้เอง subscription ที่มีอยู่จึงยังได้ข้อมูลเต็มแถวเหมือนเดิม จนกว่าจะเติม select เข้าไป ตารางที่มีคอลัมน์ขนาดใหญ่อย่าง bytea jsonb หรือ text จะเห็นผลจากวิธีนี้ชัดที่สุด
ทำไมสองเรื่องนี้ไปโผล่ที่บิล

Realtime คิดเงินตามจำนวน message และปริมาณข้อมูลที่ส่งออก การเปลี่ยนแปลงหนึ่งครั้งในฐานข้อมูลจะนับเป็นหนึ่ง message สำหรับ client แต่ละตัวที่สมัครฟังอยู่ ดังนั้นทุกเหตุการณ์ที่ตัวกรองปฏิเสธจึงลดไปหนึ่ง message ต่อผู้ฟังหนึ่งราย ส่วน select ทำให้ payload ของเหตุการณ์ที่ยังส่งถึงผู้ฟังมีขนาดเล็กลง ปริมาณข้อมูลที่ส่งออกต่อผู้ฟังแต่ละรายจึงลดลงด้วย งานที่แอปทำยังเท่าเดิม แต่ยอดที่นำไปคิดเงินลดลงทั้งสองทาง
Supabase ไม่ได้ระบุว่าจะลดลงกี่เปอร์เซ็นต์ เพราะตัวเลขจริงขึ้นอยู่กับว่าตัวกรองปฏิเสธเหตุการณ์ไปมากแค่ไหน มีผู้สมัครฟังกี่ราย และข้อมูลเต็มแถวที่เคยส่งมานั้นมีขนาดเท่าไร
เงื่อนไขที่ต้องเช็กก่อนแก้โค้ด
selectต้องใช้@supabase/supabase-jsรุ่น 2.109.0 ขึ้นไป ส่วนการต่อเงื่อนไขกรองและตัวดำเนินการชุดใหม่ ใช้กับ client library รุ่นที่ติดตั้งอยู่แล้วได้เลย- คอลัมน์ที่ใส่ใน
selectต้องเป็นคอลัมน์ที่ role ของผู้สมัครฟังอ่านได้ ส่วน Row Level Security ยังทำงานเหมือนเดิมทุกอย่าง - การใช้
selectต้องระบุschemaกับtableให้ชัดเจน จึงใช้กับ subscription แบบ wildcard ที่ฟังทั้ง schema หรือหลายตารางพร้อมกันไม่ได้ - ปกติเหตุการณ์ DELETE พกมาเฉพาะคีย์หลักของแถว จึงใช้คอลัมน์อื่นกรองเหตุการณ์ลบไม่ได้ ถ้าจะกรอง DELETE ต้องตั้ง replica identity ของตารางเป็น full ด้วยคำสั่ง
alter table messages replica identity full;เพื่อสั่งให้ Postgres แนบค่าเดิมของแถวมาทั้งในเหตุการณ์ UPDATE และ DELETE - รอบนี้มีแต่การรวมเงื่อนไขแบบ AND ยังไม่รองรับ OR
ของที่ยังไม่มี และยังไม่มีกำหนด
ตัวกรองของ Postgres Changes ยังทำได้ไม่ครบทุกแบบที่ใช้กับข้อมูลปกติ รอบนี้ยังไม่มีการเทียบค่าในอาร์เรย์และ JSON การค้นหาแบบ full-text ตัวดำเนินการช่วง รวมถึงการรวมเงื่อนไขแบบ OR และ Supabase ก็บอกตรงๆ ว่ายังไม่มีกำหนดว่าจะมาเมื่อไร ถ้าเคสที่ทำอยู่ติดข้อใดข้อหนึ่งพอดี ตอนนี้ทำได้แค่เข้าไปอธิบายสถานการณ์การใช้งานไว้ในหน้า feature requests ของ Supabase
ที่มา:
- บทความ Postgres Changes gets AND filters, new operators, and column selection จาก Supabase
- เอกสารทางการของ Postgres Changes
ชอบเรื่องแนวนี้ มีอีบุ๊คฟรีให้อ่านต่อ
ChatGPT Work ฉบับเข้าใจง่าย มอบงานให้ AI ทำจนจบ ตั้งแต่งานแรกจนถึงงานอัตโนมัติ พร้อม workflow ใช้ได้จริง 8 แบบ
กดสมัครแล้วเราจะส่งเทคนิค AI และของแจกใหม่ๆ ให้ทางอีเมล เลิกรับได้ตลอด
Claude Cowork · The Business Playbook

ฉบับภาษาไทย 15 บท เรียนรู้ผ่านโปรเจกต์จำลองต่อเนื่องทั้งเล่ม ตั้งแต่ตั้งค่า Workspace จัดการไฟล์ เชื่อมแอป ตั้งระบบอัตโนมัติ จนถึงสร้าง Plugin


