如何在 Prisma ORM 中 upsert 多个字段

22

如何使用Prisma ORM在一次查询中upsert多个字段?

我不想逐个使用upsert字段。我是否可以在一次查询中upsert所有字段?

3个回答

19

目前在Prisma中无法执行此操作。虽然有createManyupdateManydeleteMany,但没有upsertMany。(文档

如果需要处理大量数据,则最有效的方法可能是:

prisma.$transaction([
  prisma.posts.deleteMany({ where: { userId: 1 } }),
  prisma.posts.createMany({
    { id: 1, title: 'first',  userId: 1 },
    { id: 2, title: 'second', userId: 1 },
    { id: 3, title: 'third',  userId: 1 },
  }),
]);

所以你删除现有的记录,然后在事务内重新创建它们。

1
有没有更有效的方法来检索数据的最终更新状态,而不是在事务结束时进行第三个 prisma.posts.findMany({ where: { userId: 1 }}) 调用? - kevscript
1
deleteMany 会级联删除其他表中的行吗? - devordem
1
取决于你的设置,但是通常而言,是的,可能会这样。 - Danila
2
对我来说,这些记录有很多依赖关系,我不能直接删除它们,否则会违反很多约束条件。 - Pencilcheck

5

7
“ON CONFLICT DO NOTHING” 不会更新现有记录,这并不是所需的。不幸的是,尽管这个功能非常受欢迎,但它目前还不可用。 - radzserg
1
我认为这不是原始问题的要求,因为skipDuplicates不会“更新”现有记录,而是跳过它们。 - Pencilcheck
谢谢。我希望Sqlite能够支持这个功能。 - undefined

0
尝试使用deleteMany然后createMany可能不起作用,因为在尝试删除记录时存在关系约束。如果是这种情况,其中一个最佳答案对您来说将不起作用。
另一个选择是,虽然有updateMany,但它不能按我们希望的方式进行更新--它可以将多条记录都更新为相同的值。所以不幸的是,您将不得不逐个更新记录。
遗憾的是,createManyskipDuplicates标志一起使用时不会返回已创建的记录。如果是这样的话,我们可以找到返回记录与未创建的记录之间的差异,并更新未创建的记录。
攻略:
1. 查找多个记录 2. 更新多个记录 3. 创建多个记录 4. 可选:如果需要返回结果,再次查找多个记录
示例:
在这个示例中,假设我们有一个商家表,商家名称上有唯一约束,因此我们可以利用它来进行更新,而不需要像ID这样的东西,这使我们可以假设记录可能存在或不存在。
这感觉不太好,你真正获得的唯一好处就是createMany。如果你没有太多记录,最好使用prisma的upsert。如果你有大量记录,那么也许这条路值得一试。
function async upsertMerchant(merchants: Merchant[]) {
  const merchantNames = merchants.map((merchant) => merchant.name)

  const existingMerchants = await prisma.findMany({
    where: {
      name: {
        in: merchantNames,
      },
    },
  })

  // For a quick lookup
  const existingMerchantNames = new Set(existingMerchants.map((merchant) => merchant.name))

  // This could be a reduce instead if you would like.
  // I figured this is easier to follow for most folks.
  const merchantsToCreate: Merchant[] = []

  merchants.forEach((merchant) => {
    if (existingMerchantNames.has(merchant.name)) {
      await prisma.merchant.update({
        where: {
          name: merchant.name,
        },
        data: merchant,
      })
    } else {
      merchantsToCreate.push(merchant)
    }
  })

  await prisma.merchant.createMany({
    data: merchantsToCreate,
    skipDuplicates: true, // optional, there should not be duplicates, unless other code is racing you in concurrency.
  })

  // Optional if you want all the merchants back
  // This should return all newly created and previously existing records with updated information.
  return Prisma.merchants.findMany({
    where: {
      name: {
        in: merchantNames,
      },
    },
  })
}

总结

正如我之前所说,如果你有大量的记录,使用createMany可能会更高效,否则你只能逐个更新记录。如果你可以使用deleteMany,那是一种更快、更高效的方法,但如果你有关联关系,可能不是一个选择。

如果你处理的记录不多,最简单的方法可能是循环遍历并利用Prisma的upsert功能。这肯定会导致更易读的代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接