示例说明
Supabase 把 PostgreSQL 的能力直接暴露给前端与边缘环境:select 链式的 eq、gte、order 对应 SQL 谓词,行级安全策略决定可见范围;upsert 的 onConflict 对应 ON CONFLICT 主键合并语义;realtime 通道基于 WAL 广播表变更,让客户端免轮询感知数据更新。
技术要点
- 链式过滤器编译为参数化 SQL
- range 实现服务端分页窗口
- removeChannel 释放实时订阅资源
代码解读
查询语句按状态与更新时间过滤并按时间倒序取前二十条,error 需要显式判空后继续;upsert 以 id 为冲突键,存在即更新不存在即插入。subscribe 建立变更监听后演示收尾调用 removeChannel,防止悬挂的 websocket 连接拖住运行时。
使用建议
anon key 依赖行级安全策略兜底,绝不要把 service key 发到浏览器。实时订阅在组件卸载时必须移除,否则泄漏累积。分页深度大时改用游标条件(updated_at 小于上次值)替代 range 偏移。
代码示例
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
{ persistSession: false },
);
const { data: active, error } = await supabase
.from('projects')
.select('id, name, owner_id, updated_at')
.eq('status', 'active')
.gte('updated_at', '2026-10-01')
.order('updated_at', { ascending: false })
.range(0, 19);
if (error) throw new Error(error.message);
const { data: upserted } = await supabase
.from('projects')
.upsert({ id: 77, name: 'pipeline', status: 'active' }, { onConflict: 'id' })
.select();
const channel = supabase
.channel('projects-changes')
.on('postgres_changes', { event: '*', schema: 'public', table: 'projects' },
(payload) => console.log('change:', payload.event))
.subscribe();
await new Promise((r) => setTimeout(r, 1000));
supabase.removeChannel(channel);
console.log('active projects:', active.length, 'upserted:', upserted.length);