如何用supabase-js执行Upsert并返回全部目标记录?
解决Supabase upsert后返回所有目标记录的问题
当前使用upsert+ignoreDuplicates: true+select的方式只能返回新增插入的行,要实现无论记录新增还是已存在都返回所有目标记录,可以采用以下两种简洁方案:
方案一:利用伪更新返回冲突行
PostgreSQL的ON CONFLICT DO NOTHING不会返回冲突的已存在记录,但DO UPDATE会返回被操作的行。我们可以设置一个无实际修改的更新操作,既不改变原有数据,又能让Supabase返回冲突的记录:
const values = await supabase.from(user_reftext) .upsert(dataArray, { onConflict: 'col_a, col_b', // 设置无实际意义的更新,触发返回冲突行 update: { col_a: supabase.raw('col_a') } }) .select()
注意事项:
- 该操作会触发表上的UPDATE触发器(如果存在),若业务依赖更新逻辑,需评估影响。
- 可替换为任意表中存在的字段,比如
col_b: supabase.raw('col_b'),核心是不修改原有数据。
方案二:分两步查询+插入,合并结果
如果不想触发UPDATE相关逻辑,可拆分操作:先查询已存在的记录,再插入不存在的记录,最后合并两组结果:
// 提取所有要操作的联合键组合 const keyPairs = dataArray.map(item => ({ col_a: item.col_a, col_b: item.col_b })); // 第一步:查询已存在的记录 const { data: existingRecords, error: queryErr } = await supabase .from(user_reftext) .select() .or(keyPairs.map(pair => `col_a.eq.${pair.col_a},col_b.eq.${pair.col_b}`).join(',')); if (queryErr) { throw queryErr; } // 第二步:过滤出不存在的记录并插入 const newRecordsToInsert = dataArray.filter(item => { return !existingRecords.some(record => record.col_a === item.col_a && record.col_b === item.col_b ); }); const { data: insertedRecords, error: insertErr } = await supabase .from(user_reftext) .upsert(newRecordsToInsert, { onConflict: 'col_a, col_b', ignoreDuplicates: true }) .select(); if (insertErr) { throw insertErr; } // 合并得到所有目标记录 const allTargetRecords = [...existingRecords, ...insertedRecords];
优势:
- 不会触发UPDATE操作,避免不必要的触发器执行。
- 逻辑直观,易于理解和维护。
内容的提问来源于stack exchange,提问作者joudan
相关产品推荐
相关产品推荐

