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

如何用Prisma在单查询中批量添加视频至播放列表(避免重复)

问题描述

我有Playlist和Video模型,二者为显式多对多关系(用于存储额外数据)。现在我手里有一个Video主键(URL)数组,想把这些视频添加到指定播放列表中,且仅添加不存在的视频。

目前我能实现单次添加一个视频的逻辑(示例代码如下),但想知道是否可以批量添加多个视频,最好通过单个查询完成。我知道upsert可以实现“不存在则创建,存在则更新”,但设置空update的方式流程复杂,而且不确定该从哪个入口编写批量查询:是通过update Playlist模型创建多个关联?还是updateMany Video模型?或是直接操作关联表?

现有单条添加代码:

const id = /* Playlist的ID */
const videoUrl = /* Video的URL,作为主键 */
// 我想使用videoUrls数组,而不是单个videoUrl

const updatedPlaylist = await prisma.playlist.update({
  where: { id },
  include: { videos: { include: { video: true } } },
  data: {
    videos: {
      upsert: {
        where: {
          playlistId_videoUrl: {
            playlistId: id,
            videoUrl: videoUrl,
          },
        },
        create: {
          addedAt: new Date(),
          video: {
            connect: { url: videoUrl },
          },
        },
        update: {},
      },
    },
  },
});
解决方案

方法1:直接操作中间关联表(推荐,单查询批量添加)

因为是显式多对多关系,Prisma会生成对应的中间模型(比如PlaylistVideo,包含playlistId、videoUrl、addedAt等字段,且复合主键为playlistId_videoUrl)。你可以直接对这个中间模型使用createMany,并开启skipDuplicates参数来忽略已存在的关联:

const playlistId = /* Playlist的ID */
const videoUrls = ["url1", "url2", "url3"]; // 你的视频URL数组

await prisma.playlistVideo.createMany({
  data: videoUrls.map(url => ({
    playlistId,
    videoUrl: url,
    addedAt: new Date()
  })),
  skipDuplicates: true // 关键:忽略已存在的复合主键记录,不会报错
});

// 如需返回更新后的Playlist及关联视频,再单独查询一次
const updatedPlaylist = await prisma.playlist.findUnique({
  where: { id: playlistId },
  include: { videos: { include: { video: true } } }
});

这个方法的优势是单查询完成批量插入,skipDuplicates会自动跳过已存在的playlistId+videoUrl组合,无需额外判断。

方法2:通过Playlist的update操作批量创建关联

如果你希望在同一个查询中完成更新并返回结果,可以在playlist.update的data.videos里使用create数组,结合connect,但需要注意:这种方式如果有重复的关联会报错,所以需要先查询出播放列表已有的视频URL,过滤掉重复项后再创建:

const playlistId = /* Playlist的ID */
const videoUrls = ["url1", "url2", "url3"];

// 先查询已存在的关联视频URL
const existingPlaylist = await prisma.playlist.findUnique({
  where: { id: playlistId },
  select: { videos: { select: { videoUrl: true } } }
});
const existingVideoUrls = existingPlaylist.videos.map(item => item.videoUrl);

// 过滤出需要新增的视频URL
const newVideoUrls = videoUrls.filter(url => !existingVideoUrls.includes(url));

// 批量创建关联
const updatedPlaylist = await prisma.playlist.update({
  where: { id: playlistId },
  include: { videos: { include: { video: true } } },
  data: {
    videos: {
      create: newVideoUrls.map(url => ({
        addedAt: new Date(),
        video: { connect: { url } }
      }))
    }
  }
});

这个方法需要两次查询,但可以直接返回更新后的Playlist对象。如果你的业务场景允许先查询再过滤,这种方式也能满足需求。

注意事项

Prisma目前不支持在update的关联操作中批量使用upsert,只能单个指定。所以用createMany + skipDuplicates是最简洁的批量去重添加方式。

内容的提问来源于stack exchange,提问作者N.T. Dang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 22:53:05