fix-book5-structure.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /**
  2. * 修复 Book 5 的章节数据混乱问题
  3. *
  4. * 问题:大量 level=1 但 number > 20 的异常记录(这些本应是 level=3 的小节)
  5. * 还有些节的 parentId 指向了这些异常的 level=1 记录
  6. */
  7. const { PrismaClient } = require('./node_modules/@prisma/client');
  8. const prisma = new PrismaClient();
  9. async function main() {
  10. const bookId = 5;
  11. console.log('=== 开始修复 Book 5 章节数据 ===\n');
  12. // 1. 找出正常的章(level=1, number <= 20, parentId=0)
  13. const normalChapters = await prisma.bookChapter.findMany({
  14. where: { bookId, level: 1, parentId: 0, number: { lte: 20 } },
  15. orderBy: { number: 'asc' },
  16. });
  17. console.log('正常章:', normalChapters.map(c => `ID=${c.id}, number=${c.number}`).join(', '));
  18. // 2. 找出所有 level=1 但 number > 20 或 parentId != 0 的异常记录
  19. const abnormalLevel1 = await prisma.bookChapter.findMany({
  20. where: {
  21. bookId,
  22. level: 1,
  23. OR: [
  24. { number: { gt: 20 } },
  25. { parentId: { not: 0 } }
  26. ]
  27. },
  28. orderBy: { number: 'asc' },
  29. });
  30. console.log(`\n发现 ${abnormalLevel1.length} 条 level=1 的异常记录:`);
  31. abnormalLevel1.forEach(r => console.log(` ID=${r.id}, number=${r.number}, parentId=${r.parentId}, title=${r.title.substring(0, 40)}`));
  32. // 3. 找出所有 level=2 且 parentId 指向异常 level=1 记录的节
  33. const abnormalParentIds = abnormalLevel1.map(r => r.id);
  34. const sectionsWithAbnormalParent = await prisma.bookChapter.findMany({
  35. where: {
  36. bookId,
  37. level: 2,
  38. parentId: { in: abnormalParentIds }
  39. }
  40. });
  41. console.log(`\n发现 ${sectionsWithAbnormalParent.length} 条节指向异常父节点:`);
  42. sectionsWithAbnormalParent.forEach(r => console.log(` ID=${r.id}, number=${r.number}, parentId=${r.parentId}`));
  43. // 4. 删除策略:
  44. // a. 先删除所有 level=3 且 parentId 指向异常节或异常章的记录
  45. // b. 删除所有 level=2 且 parentId 指向异常 level=1 的记录
  46. // c. 删除所有异常的 level=1 记录
  47. // 收集所有需要删除的 parentId
  48. const abnormalSectionIds = sectionsWithAbnormalParent.map(r => r.id);
  49. const abnormalChapterIds = abnormalLevel1.map(r => r.id);
  50. const allInvalidParentIds = [...abnormalSectionIds, ...abnormalChapterIds];
  51. // 4a. 删除 level=3 且 parentId 指向无效父节点的记录
  52. if (allInvalidParentIds.length > 0) {
  53. const deleteLevel3 = await prisma.bookChapter.deleteMany({
  54. where: {
  55. bookId,
  56. level: 3,
  57. parentId: { in: allInvalidParentIds }
  58. }
  59. });
  60. console.log(`\n删除 ${deleteLevel3.count} 条 level=3 记录(parentId 指向无效父节点)`);
  61. }
  62. // 4b. 删除 level=2 且 parentId 指向异常 level=1 的记录
  63. if (abnormalParentIds.length > 0) {
  64. const deleteLevel2 = await prisma.bookChapter.deleteMany({
  65. where: {
  66. bookId,
  67. level: 2,
  68. parentId: { in: abnormalParentIds }
  69. }
  70. });
  71. console.log(`删除 ${deleteLevel2.count} 条 level=2 记录(parentId 指向异常 level=1)`);
  72. }
  73. // 4c. 删除异常的 level=1 记录
  74. if (abnormalLevel1.length > 0) {
  75. const deleteLevel1 = await prisma.bookChapter.deleteMany({
  76. where: {
  77. id: { in: abnormalLevel1.map(r => r.id) }
  78. }
  79. });
  80. console.log(`删除 ${deleteLevel1.count} 条异常 level=1 记录`);
  81. }
  82. // 5. 验证修复结果
  83. console.log('\n=== 修复后验证 ===');
  84. const remainingLevel1 = await prisma.bookChapter.count({
  85. where: { bookId, level: 1, parentId: 0 }
  86. });
  87. console.log(`剩余 level=1 记录: ${remainingLevel1} 条`);
  88. const remainingLevel2 = await prisma.bookChapter.count({
  89. where: { bookId, level: 2 }
  90. });
  91. console.log(`剩余 level=2 记录: ${remainingLevel2} 条`);
  92. const remainingLevel3 = await prisma.bookChapter.count({
  93. where: { bookId, level: 3 }
  94. });
  95. console.log(`剩余 level=3 记录: ${remainingLevel3} 条`);
  96. // 6. 显示修复后的正常结构
  97. console.log('\n修复后的章结构:');
  98. const chaptersAfter = await prisma.bookChapter.findMany({
  99. where: { bookId, level: 1, parentId: 0 },
  100. orderBy: { number: 'asc' },
  101. select: { id: true, number: true, title: true }
  102. });
  103. chaptersAfter.forEach(c => console.log(` [章${c.number}] ID=${c.id}: ${c.title}`));
  104. console.log('\n修复后的节数量分布:');
  105. for (const chapter of chaptersAfter) {
  106. const sectionsCount = await prisma.bookChapter.count({
  107. where: { bookId, level: 2, parentId: chapter.id }
  108. });
  109. console.log(` 章${chapter.number} (ID=${chapter.id}): ${sectionsCount} 个节`);
  110. }
  111. }
  112. main()
  113. .catch(console.error)
  114. .finally(() => prisma.$disconnect());