You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中监听Supabase内用户位置指定半径内的表插入事件

解决Supabase Realtime监听指定半径内插入操作的问题

问题根源

你当前的写法无效,是因为Supabase Realtime的PostgresChangeFilter不允许在column字段中直接使用SQL空间函数(比如ST_Distance),column参数只能指定表的实际列名,无法解析复杂表达式。


可行解决方案

方案1:使用自定义SQL过滤器(Realtime v2支持)

如果你的Supabase使用Realtime v2,可以通过filter的custom类型直接编写WHERE条件表达式,实现基于空间距离的过滤:

late RealtimeChannel _violationsListener;

void subscribeToViolations(LatLng userLocation) {
  const radius = 10000; // 10公里(米)
  // 用ST_DistanceSphere计算实际米数距离,避免经纬度度数的误差
  final filterSql = '''
    ST_DistanceSphere(reporting_location, ST_SetSRID(ST_MakePoint(${userLocation.longitude}, ${userLocation.latitude}), 4326)) < $radius
  ''';

  // 频道名带上位置参数,避免用户位置变化时的订阅冲突
  _violationsListener = supabase
      .channel('violations-channel-${userLocation.latitude}-${userLocation.longitude}')
      .onPostgresChanges(
        event: PostgresChangeEvent.insert,
        schema: 'public',
        table: 'violations',
        filter: PostgresChangeFilter.custom(filterSql),
        callback: (payload) async {
          final json = payload.newRecord;
          debugPrint('收到符合条件的插入记录:');
          debugPrint(json.toString());
        },
      )
      .subscribe();
}

注意:用户位置更新时,需先调用_violationsListener.unsubscribe()取消旧订阅,再重新执行上述订阅逻辑。

方案2:结合行级安全(RLS)策略

如果需要更安全的动态过滤逻辑,可以利用RLS策略结合会话变量实现:

  1. 先启用violations表的RLS:
ALTER TABLE public.violations ENABLE ROW LEVEL SECURITY;
  1. 创建RLS策略,基于会话变量过滤半径内的记录:
CREATE POLICY "Allow viewing violations within radius" ON public.violations
FOR SELECT USING (
  ST_DistanceSphere(
    reporting_location, 
    ST_SetSRID(ST_MakePoint(current_setting('app.user_longitude')::float8, current_setting('app.user_latitude')::float8), 4326)
  ) < current_setting('app.user_radius')::int
);
  1. 创建设置会话变量的存储过程:
CREATE OR REPLACE FUNCTION public.set_session_variables(user_latitude float8, user_longitude float8, user_radius int)
RETURNS void AS $$
BEGIN
  PERFORM set_config('app.user_latitude', user_latitude::text, true);
  PERFORM set_config('app.user_longitude', user_longitude::text, true);
  PERFORM set_config('app.user_radius', user_radius::text, true);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
  1. Flutter端订阅逻辑:
late RealtimeChannel _violationsListener;

void subscribeToViolations(LatLng userLocation) async {
  const radius = 10000;
  // 先设置会话变量,让RLS策略生效
  await supabase.rpc('set_session_variables', params: {
    'user_latitude': userLocation.latitude,
    'user_longitude': userLocation.longitude,
    'user_radius': radius,
  });

  // 订阅插入事件,RLS会自动过滤符合条件的记录
  _violationsListener = supabase
      .channel('violations-channel')
      .onPostgresChanges(
        event: PostgresChangeEvent.insert,
        schema: 'public',
        table: 'violations',
        callback: (payload) async {
          final json = payload.newRecord;
          debugPrint('收到符合条件的插入记录:');
          debugPrint(json.toString());
        },
      )
      .subscribe();
}

额外注意事项

  • 确保reporting_location列的类型是geometry(Point, 4326)或geography(Point, 4326),否则空间函数无法正常计算距离。
  • 用户位置更新时,同样需要取消旧订阅、重新设置会话变量并创建新订阅。

内容的提问来源于stack exchange,提问作者Tim Kariuki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 03:07:38