You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用@supabase/ssr仅Upsert非空/非undefined字段,避免覆盖数据库原有非空值

如何使用@supabase/ssr仅Upsert非空/非undefined字段,避免覆盖数据库原有非空值

嗨,这个痛点我太懂了——webhook只返回变更的字段,用普通upsert一不小心就把数据库里原有非空的字段清成null,还没法用先查后改的方案,数据量大的时候根本扛不住对吧?别担心,结合Supabase的参数和前端的数据预处理,就能完美解决这个问题!

核心思路

要实现“只更新传入的字段,保留原有值”,需要两步配合:

  1. 预处理要Upsert的数据:只保留webhook传来的存在(非undefined)的字段,过滤掉那些没传的字段;
  2. 配置Supabase Upsert的关键参数:关闭defaultToNull,告诉Supabase不要把未传入的字段设为null。

具体实现代码

先看完整的修正后的代码,我给你加了注释:

// 预处理webhook返回的联系人数据:只保留存在的字段,避免传入undefined的键
const contactsToUpsert = nextContacts.map((contact: {phone: string, name?: string, notify?: string}) => ({
  user_id: settings.user_id, // 固定要传入的关联字段
  phone: contact.phone, // webhook必传的唯一标识字段
  // 只当name确实存在(不是undefined)时,才把这个字段加入upsert对象
  ...(contact.name !== undefined && { name: contact.name }),
  // 同理处理notify字段
  ...(contact.notify !== undefined && { notify: contact.notify })
}));

// 调用Supabase的upsert,核心是配置defaultToNull: false
const { error } = await supabase
  .from('contacts')
  .upsert(contactsToUpsert, {
    onConflict: 'user_id,phone', // 联合唯一键,用来判断是插入新行还是更新已有行
    defaultToNull: false // 关键!关闭默认把未传字段设为null的行为
  });

为什么这样有效?

  • 数据预处理部分:用...(contact.name !== undefined && { name: contact.name })这种方式,只有当字段确实被webhook返回(不是undefined)时,才会被加入到upsert的对象中。那些没返回的字段,根本不会出现在提交的数据里。
  • defaultToNull: false参数:Supabase默认的upsert行为是,如果你没传某个字段,就会把该字段设为null。但当你把这个参数设为false后,Supabase生成的SQL只会更新你传入的字段,未传入的字段会保持数据库里的原有值,完全不会被改动。

额外注意点

  1. 联合唯一索引:确保你的contacts表已经给user_idphone创建了联合唯一索引,不然onConflict参数会报错——Supabase需要这个来判断是插入新行还是更新已有行。
  2. 空字符串的处理:如果你的业务允许webhook返回空字符串(比如用户主动清空了name),那不要用contact.name && ...,因为空字符串在逻辑与里会被判定为false,导致这个字段被过滤。改成contact.name !== undefined就能区分“未传字段”和“传了空字符串”的情况,确保空字符串能正常更新到数据库。

这样处理后,不管webhook返回多少个字段,都只会更新那些传过来的字段,数据库里原有的非空值绝对不会被覆盖成null,而且效率和原生upsert一样高,完全不用担心数据量大的问题!

火山引擎 最新活动