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

如何在用户连接请求的多对多表中避免重复行并适配Hasura的on_conflict参数

最优解决方案:PostgreSQL表达式唯一约束 + Hasura Upsert

这是双向邀请场景里的典型问题,核心是要让「A邀请B」和「B邀请A」被视为同一组关系,从而避免重复插入并自动合并状态。下面是最常用且适配Hasura的实现方案:

1. 在PostgreSQL中添加表达式唯一约束

不需要新增额外字段,直接利用PostgreSQL的least()和greatest()函数,对sender_id和receiver_id进行排序后创建唯一约束。这样不管双方谁作为发送方/接收方,排序后的组合都是唯一的,从数据库层面杜绝重复行。

执行以下SQL语句(可通过Hasura的SQL编辑器或直接连接Postgres执行):

ALTER TABLE invitations 
ADD CONSTRAINT unique_invitation_pair 
UNIQUE (least(sender_id, receiver_id), greatest(sender_id, receiver_id));

这个约束会确保:对于任意两个用户,不管邀请方向如何,只会存在一组对应的记录。

2. 刷新Hasura元数据

在Hasura控制台中,进入Data -> 你的表(invitations),点击右上角的「Refresh」按钮,让Hasura识别新添加的唯一约束。

3. 编写Hasura Upsert Mutation

现在可以利用Hasura的on_conflict参数,指定我们刚创建的unique_invitation_pair约束作为冲突判断条件。当检测到冲突时(即双方互相发送了邀请),自动将状态更新为connected。

示例Mutation:

mutation UpsertInvitation {
  insert_invitations(
    objects: [{sender_id: "1234", receiver_id: "6789", status: "pending"}],
    on_conflict: {
      constraint: unique_invitation_pair,
      update_columns: [status],
      _set: {status: "connected"}
    }
  ) {
    returning {
      id
      sender_id
      receiver_id
      status
    }
  }
}

逻辑说明:

  • 当插入的邀请是全新的(没有对应的反向邀请),则正常插入一条pending状态的记录。
  • 当插入的邀请已经存在反向记录(比如用户6789已经给1234发过邀请),则触发冲突逻辑,将现有记录的status更新为connected,完美解决双方同时发邀请的场景。

为什么这个方案最优?

  • 无应用层侵入:不需要在代码里对UUID排序后再插入,数据库自动处理唯一性逻辑,降低应用层复杂度。
  • Hasura原生支持:Hasura完全支持将表达式创建的唯一约束作为on_conflict的目标,不需要额外配置。
  • 性能高效:直接利用数据库的唯一索引,冲突判断和更新都是原子操作,避免竞态条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 22:42:30