/** * 修复 Book 5 的章节数据混乱问题 * * 问题:大量 level=1 但 number > 20 的异常记录(这些本应是 level=3 的小节) * 还有些节的 parentId 指向了这些异常的 level=1 记录 */ const { PrismaClient } = require('./node_modules/@prisma/client'); const prisma = new PrismaClient(); async function main() { const bookId = 5; console.log('=== 开始修复 Book 5 章节数据 ===\n'); // 1. 找出正常的章(level=1, number <= 20, parentId=0) const normalChapters = await prisma.bookChapter.findMany({ where: { bookId, level: 1, parentId: 0, number: { lte: 20 } }, orderBy: { number: 'asc' }, }); console.log('正常章:', normalChapters.map(c => `ID=${c.id}, number=${c.number}`).join(', ')); // 2. 找出所有 level=1 但 number > 20 或 parentId != 0 的异常记录 const abnormalLevel1 = await prisma.bookChapter.findMany({ where: { bookId, level: 1, OR: [ { number: { gt: 20 } }, { parentId: { not: 0 } } ] }, orderBy: { number: 'asc' }, }); console.log(`\n发现 ${abnormalLevel1.length} 条 level=1 的异常记录:`); abnormalLevel1.forEach(r => console.log(` ID=${r.id}, number=${r.number}, parentId=${r.parentId}, title=${r.title.substring(0, 40)}`)); // 3. 找出所有 level=2 且 parentId 指向异常 level=1 记录的节 const abnormalParentIds = abnormalLevel1.map(r => r.id); const sectionsWithAbnormalParent = await prisma.bookChapter.findMany({ where: { bookId, level: 2, parentId: { in: abnormalParentIds } } }); console.log(`\n发现 ${sectionsWithAbnormalParent.length} 条节指向异常父节点:`); sectionsWithAbnormalParent.forEach(r => console.log(` ID=${r.id}, number=${r.number}, parentId=${r.parentId}`)); // 4. 删除策略: // a. 先删除所有 level=3 且 parentId 指向异常节或异常章的记录 // b. 删除所有 level=2 且 parentId 指向异常 level=1 的记录 // c. 删除所有异常的 level=1 记录 // 收集所有需要删除的 parentId const abnormalSectionIds = sectionsWithAbnormalParent.map(r => r.id); const abnormalChapterIds = abnormalLevel1.map(r => r.id); const allInvalidParentIds = [...abnormalSectionIds, ...abnormalChapterIds]; // 4a. 删除 level=3 且 parentId 指向无效父节点的记录 if (allInvalidParentIds.length > 0) { const deleteLevel3 = await prisma.bookChapter.deleteMany({ where: { bookId, level: 3, parentId: { in: allInvalidParentIds } } }); console.log(`\n删除 ${deleteLevel3.count} 条 level=3 记录(parentId 指向无效父节点)`); } // 4b. 删除 level=2 且 parentId 指向异常 level=1 的记录 if (abnormalParentIds.length > 0) { const deleteLevel2 = await prisma.bookChapter.deleteMany({ where: { bookId, level: 2, parentId: { in: abnormalParentIds } } }); console.log(`删除 ${deleteLevel2.count} 条 level=2 记录(parentId 指向异常 level=1)`); } // 4c. 删除异常的 level=1 记录 if (abnormalLevel1.length > 0) { const deleteLevel1 = await prisma.bookChapter.deleteMany({ where: { id: { in: abnormalLevel1.map(r => r.id) } } }); console.log(`删除 ${deleteLevel1.count} 条异常 level=1 记录`); } // 5. 验证修复结果 console.log('\n=== 修复后验证 ==='); const remainingLevel1 = await prisma.bookChapter.count({ where: { bookId, level: 1, parentId: 0 } }); console.log(`剩余 level=1 记录: ${remainingLevel1} 条`); const remainingLevel2 = await prisma.bookChapter.count({ where: { bookId, level: 2 } }); console.log(`剩余 level=2 记录: ${remainingLevel2} 条`); const remainingLevel3 = await prisma.bookChapter.count({ where: { bookId, level: 3 } }); console.log(`剩余 level=3 记录: ${remainingLevel3} 条`); // 6. 显示修复后的正常结构 console.log('\n修复后的章结构:'); const chaptersAfter = await prisma.bookChapter.findMany({ where: { bookId, level: 1, parentId: 0 }, orderBy: { number: 'asc' }, select: { id: true, number: true, title: true } }); chaptersAfter.forEach(c => console.log(` [章${c.number}] ID=${c.id}: ${c.title}`)); console.log('\n修复后的节数量分布:'); for (const chapter of chaptersAfter) { const sectionsCount = await prisma.bookChapter.count({ where: { bookId, level: 2, parentId: chapter.id } }); console.log(` 章${chapter.number} (ID=${chapter.id}): ${sectionsCount} 个节`); } } main() .catch(console.error) .finally(() => prisma.$disconnect());