← 中文资源

简体中文版本

Supabase 客户端过滤查询

用 Supabase 客户端链式过滤查询表数据:range 分页、upsert 冲突子句、实时变更订阅与退出时的通道清理。

阅读英文原文

示例说明

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);