如何通过Prisma为含两个多对多自关联的MongoDB集合正确植入数据
批量导入Prisma自关联ChapterSegment数据的高效方案
核心思路
先批量创建所有基础记录,再基于预定义的关联关系更新successorIds和predecessorIds数组。这种方式避开了嵌套创建的递归复杂度,也无需手动逐个维护connect关联,适合大量数据导入场景。
具体实现步骤
1. 整理导入数据
先把待导入的片段数据整理成包含临时标识(用于关联映射)、所属章节ID、前驱/后继临时标识的结构:
// 示例原始数据,tempKey用于后续关联映射,可自定义唯一标识 const rawSegments = [ { tempKey: 'intro', chapterId: '章节目录ID1', successorTempKeys: ['content1'], predecessorTempKeys: [] }, { tempKey: 'content1', chapterId: '章节目录ID1', successorTempKeys: ['content2', 'sidebar1'], predecessorTempKeys: ['intro'] }, { tempKey: 'content2', chapterId: '章节目录ID1', successorTempKeys: ['summary'], predecessorTempKeys: ['content1'] }, { tempKey: 'sidebar1', chapterId: '章节目录ID1', successorTempKeys: ['summary'], predecessorTempKeys: ['content1'] }, { tempKey: 'summary', chapterId: '章节目录ID1', successorTempKeys: [], predecessorTempKeys: ['content2', 'sidebar1'] }, // ... 更多批量数据 ];
2. 批量创建基础记录并建立ID映射
用Promise.all批量创建所有片段,同时记录临时标识与生成的MongoDB ObjectId的映射关系:
const segmentIdMap = new Map<string, string>(); // 批量创建基础片段(暂不设置关联) await Promise.all( rawSegments.map(async (seg) => { const createdSegment = await prisma.chapterSegment.create({ data: { chapterId: seg.chapterId, successorIds: [], predecessorIds: [], }, }); segmentIdMap.set(seg.tempKey, createdSegment.id); }) );
3. 批量更新关联字段
基于ID映射关系,批量更新每个片段的successorIds和predecessorIds数组:
await Promise.all( rawSegments.map(async (seg) => { // 将临时标识转换为实际的ObjectId const successorIds = seg.successorTempKeys.map(key => segmentIdMap.get(key)!); const predecessorIds = seg.predecessorTempKeys.map(key => segmentIdMap.get(key)!); await prisma.chapterSegment.update({ where: { id: segmentIdMap.get(seg.tempKey)! }, data: { successorIds, predecessorIds, }, }); }) );
4. (可选)用事务保证原子性
如果需要确保创建和更新操作的原子性(避免部分数据导入失败),可以将上述逻辑包裹在Prisma事务中:
await prisma.$transaction(async (tx) => { const segmentIdMap = new Map<string, string>(); // 事务内创建所有片段 await Promise.all( rawSegments.map(async (seg) => { const createdSegment = await tx.chapterSegment.create({ data: { chapterId: seg.chapterId, successorIds: [], predecessorIds: [], }, }); segmentIdMap.set(seg.tempKey, createdSegment.id); }) ); // 事务内批量更新关联 await Promise.all( rawSegments.map(async (seg) => { const successorIds = seg.successorTempKeys.map(key => segmentIdMap.get(key)!); const predecessorIds = seg.predecessorTempKeys.map(key => segmentIdMap.get(key)!); await tx.chapterSegment.update({ where: { id: segmentIdMap.get(seg.tempKey)! }, data: { successorIds, predecessorIds, }, }); }) ); });
简化场景:已有预设ObjectId
如果你的原始数据已经包含有效的MongoDB ObjectId(比如从其他系统导出),可以直接在创建时指定ID和关联数组,无需后续更新:
// 原始数据已包含预设的ObjectId const rawSegments = [ { id: '60d21b4667d0d8992e610c85', chapterId: '章节目录ID1', successorIds: ['60d21b4667d0d8992e610c86'], predecessorIds: [] }, { id: '60d21b4667d0d8992e610c86', chapterId: '章节目录ID1', successorIds: ['60d21b4667d0d8992e610c87'], predecessorIds: ['60d21b4667d0d8992e610c85'] }, // ... 更多数据 ]; // 直接批量创建,关联数组会自动生效 await prisma.chapterSegment.createMany({ data: rawSegments, });
关键说明
你的Prisma模型已经显式定义了successorIds和predecessorIds数组字段,直接更新这些数组比使用connect操作更高效。模型中的successors和predecessors关联字段会自动基于这些ID数组提供关联查询能力,无需额外配置。
内容的提问来源于stack exchange,提问作者Lennart Stoop
相关产品推荐
相关产品推荐

