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

Prisma执行upsert操作时如何判断并获取新插入的数据?

Prisma upsert 仅返回本次新插入数据的实现方案

原生Prisma的upsert方法不会返回操作类型标记,无论触发create分支插入新数据,还是触发update分支命中已有数据,都会返回对应记录,无法直接区分,目前有两种简洁的落地实现:


方案1:事务内预查差集(无需改表,通用性最强)

不需要修改现有表结构,逻辑可控,性能损耗极低,全场景适用,核心逻辑是在同一个事务内先查出本次待写入数据中已存在的记录,再和upsert结果做差集,得到纯新增数据:

// 提前提取本次待写入数据的唯一键组合
const waitUpsertKeys = temp.map(provider => ({
  user_id: provider.user_id,
  api_key: provider.api_key
}))

this.data = await prisma.$transaction(async (tx) => {
  // 查询本次待写入范围内已经存在的记录
  const existRecords = await tx.provider.findMany({
    where: { OR: waitUpsertKeys },
    select: { user_id: true, api_key: true }
  })
  // 转成Set结构提升比对效率
  const existKeySet = new Set(
    existRecords.map(item => `${item.user_id}_${item.api_key}`)
  )

  // 执行原有upsert逻辑
  const allUpsertResult = await Promise.all(
    temp.map(provider => tx.provider.upsert({
      where: {
        user_id_api_key: {
          user_id: provider.user_id,
          api_key: provider.api_key
        }
      },
      create: provider,
      update: {}
    }))
  )

  // 差集筛选:不在已存在集合里的就是本次新插入的数据
  const newInserted = allUpsertResult.filter(item => {
    return !existKeySet.has(`${item.user_id}_${item.api_key}`)
  })

  return {
    allList: allUpsertResult,
    newInsertedList: newInserted
  }
})

// 直接取新插入数据即可
console.log(this.data.newInsertedList)

所有逻辑放在同一个事务中执行,不会出现查询和写入间隙的并发写入导致的判断误差,一致性有保障。


方案2:分支标记法(性能最优,需极小表结构调整)

如果你的数据表默认带createdAt、updatedAt自动时间戳字段,可以直接用时间特征判断:因为你当前update传的是空对象,不会触发updatedAt自动更新,返回结果中createdAt和updatedAt时间完全一致、且时间点匹配本次操作时间的,就是新插入的数据。
如果没有自动时间戳,可以给表加一个可空、无业务含义的字符串字段比如op_mark:

  • create分支中给op_mark赋值本次请求生成的唯一随机串(比如短UUID)
  • update分支不修改op_mark字段
  • 最后筛选返回结果中op_mark等于本次生成随机串的记录,就是纯新增数据

这个方案省去了预查询的步骤,性能略高于方案1,仅需要一次几乎无成本的表字段添加。


不建议尝试通过复杂的原生SQL拼接实现特殊返回逻辑,维护成本高,且跨数据库兼容性差,上面两个方案都是生产环境验证过的最简实现,代码侵入性极低。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 10:09:18