Files
huike-back/docs/course-domain-jsonb-migration-runbook.md
T
weli 15dc2c1a3c refactor course_category naming and add jsonb migration runbook
Rename remaining qumu_category db artifacts to course_category and document jsonb key migration procedure for existing production data.

Made-with: Cursor
2026-04-23 21:39:13 +08:00

5.4 KiB
Raw Blame History

教学域命名重构:JSONB 数据迁移手册

1. 结论先看

  • JSONB 结构字段已在 Rust 代码中切换为 course_* 命名。
  • 已新增并提交 JSONB 存量迁移脚本(up/down.sql)。
  • 对于线上已有数据,仍需要按本手册执行 migration + 校验,确保旧键 qumu_* 全量迁移到 course_*

2. 代码与迁移现状

2.1 Rust 结构已改为 course_*

核心结构体(htyws_models):

  • CourseSectionJsonData 使用:
    • course_id
    • course_type
    • course_name
    • course_text
    • course_category_key
    • course_category_name

并且 daka/jihua/kecheng 相关请求与模型字段已统一到 course_sections

2.2 JSONB 存量迁移脚本

已存在以下 migration

  • htyws_models/migrations/2026-04-23-100003_migrate_qumu_jsonb_keys_to_course

    • 迁移对象:daka.course_sectionsjihua.course_sections
    • 逻辑:使用 jsonb_array_elements + jsonb_agg 重组 vals 数组元素,将 qumu_* 改为 course_*
  • htykc_models/migrations/2026-04-23-100004_migrate_qumu_jsonb_keys_to_course

    • 迁移对象:kecheng.course_sections
    • 逻辑:同上

3. 迁移前检查

3.1 数据库与权限

确认目标库可连接并有执行 migration 权限:

\c htyws_local
SELECT current_user, current_database();

htykc_local 同样检查。

3.2 迁移前数据基线(建议保存结果)

htyws_local

-- daka 中仍含 qumu_* 键的记录数
SELECT count(*) AS daka_rows_with_qumu_keys
FROM daka
WHERE course_sections IS NOT NULL
  AND EXISTS (
    SELECT 1
    FROM jsonb_array_elements(course_sections->'vals') AS item
    WHERE item ? 'qumu_id'
       OR item ? 'qumu_type'
       OR item ? 'qumu_name'
       OR item ? 'qumu_text'
       OR item ? 'qumu_category_key'
       OR item ? 'qumu_category_name'
  );

-- jihua 中仍含 qumu_* 键的记录数
SELECT count(*) AS jihua_rows_with_qumu_keys
FROM jihua
WHERE course_sections IS NOT NULL
  AND EXISTS (
    SELECT 1
    FROM jsonb_array_elements(course_sections->'vals') AS item
    WHERE item ? 'qumu_id'
       OR item ? 'qumu_type'
       OR item ? 'qumu_name'
       OR item ? 'qumu_text'
       OR item ? 'qumu_category_key'
       OR item ? 'qumu_category_name'
  );

htykc_local

SELECT count(*) AS kecheng_rows_with_qumu_keys
FROM kecheng
WHERE course_sections IS NOT NULL
  AND EXISTS (
    SELECT 1
    FROM jsonb_array_elements(course_sections->'vals') AS item
    WHERE item ? 'qumu_id'
       OR item ? 'qumu_type'
       OR item ? 'qumu_name'
       OR item ? 'qumu_text'
       OR item ? 'qumu_category_key'
       OR item ? 'qumu_category_name'
  );

4. 执行步骤

4.1 执行 htyws_models migration

cd huike-back/htyws_models
DATABASE_URL=postgres://htyws@localhost/htyws_local diesel migration run

4.2 执行 htykc_models migration

cd huike-back/htykc_models
DATABASE_URL=postgres://htykc@localhost/htykc_local diesel migration run

若本地无 htykc DB 角色,先创建角色或使用可用 DB 用户连接串再执行。

5. 迁移后校验

5.1 校验旧键已清理

htyws_localhtykc_local 分别执行:

-- 应返回 0:仍包含 qumu_* 的元素数量
SELECT count(*) AS remaining_qumu_key_rows
FROM (
  SELECT item
  FROM daka, jsonb_array_elements(daka.course_sections->'vals') AS item
  WHERE daka.course_sections IS NOT NULL
  UNION ALL
  SELECT item
  FROM jihua, jsonb_array_elements(jihua.course_sections->'vals') AS item
  WHERE jihua.course_sections IS NOT NULL
) t
WHERE item ? 'qumu_id'
   OR item ? 'qumu_type'
   OR item ? 'qumu_name'
   OR item ? 'qumu_text'
   OR item ? 'qumu_category_key'
   OR item ? 'qumu_category_name';

htykc_local 可单独查:

SELECT count(*) AS remaining_qumu_key_rows
FROM (
  SELECT item
  FROM kecheng, jsonb_array_elements(kecheng.course_sections->'vals') AS item
  WHERE kecheng.course_sections IS NOT NULL
) t
WHERE item ? 'qumu_id'
   OR item ? 'qumu_type'
   OR item ? 'qumu_name'
   OR item ? 'qumu_text'
   OR item ? 'qumu_category_key'
   OR item ? 'qumu_category_name';

5.2 校验新键可读

SELECT count(*) AS rows_with_course_id
FROM (
  SELECT item
  FROM daka, jsonb_array_elements(daka.course_sections->'vals') AS item
  WHERE daka.course_sections IS NOT NULL
  UNION ALL
  SELECT item
  FROM jihua, jsonb_array_elements(jihua.course_sections->'vals') AS item
  WHERE jihua.course_sections IS NOT NULL
) t
WHERE item ? 'course_id';

6. 回滚方案

若需要回滚 JSONB 键名,可执行:

cd huike-back/htyws_models
DATABASE_URL=postgres://htyws@localhost/htyws_local diesel migration revert

cd huike-back/htykc_models
DATABASE_URL=postgres://htykc@localhost/htykc_local diesel migration revert

对应 down.sql 会将 course_* 键改回 qumu_*

7. 上线建议顺序

  1. 先部署支持新字段命名的后端代码。
  2. 执行 DB migration(表/列 + JSONB 键)。
  3. 执行上述 SQL 校验。
  4. 再部署前端。
  5. 观察日志与关键功能(课程、课程分组、计划、打卡、排课)至少一个业务周期。

8. 风险提示

  • JSONB 迁移依赖 course_sections->'vals' 是数组结构;若历史脏数据不满足该结构,可能迁移失败。
  • 执行前建议做 DB 备份或快照。
  • 若线上写流量较高,建议在低峰期执行并观察慢查询。