15dc2c1a3c
Rename remaining qumu_category db artifacts to course_category and document jsonb key migration procedure for existing production data. Made-with: Cursor
5.4 KiB
5.4 KiB
教学域命名重构:JSONB 数据迁移手册
1. 结论先看
- JSONB 结构字段已在 Rust 代码中切换为
course_*命名。 - 已新增并提交 JSONB 存量迁移脚本(
up/down.sql)。 - 对于线上已有数据,仍需要按本手册执行 migration + 校验,确保旧键
qumu_*全量迁移到course_*。
2. 代码与迁移现状
2.1 Rust 结构已改为 course_*
核心结构体(htyws_models):
CourseSectionJsonData使用:course_idcourse_typecourse_namecourse_textcourse_category_keycourse_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_sections、jihua.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
若本地无
htykcDB 角色,先创建角色或使用可用 DB 用户连接串再执行。
5. 迁移后校验
5.1 校验旧键已清理
在 htyws_local 与 htykc_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. 上线建议顺序
- 先部署支持新字段命名的后端代码。
- 执行 DB migration(表/列 + JSONB 键)。
- 执行上述 SQL 校验。
- 再部署前端。
- 观察日志与关键功能(课程、课程分组、计划、打卡、排课)至少一个业务周期。
8. 风险提示
- JSONB 迁移依赖
course_sections->'vals'是数组结构;若历史脏数据不满足该结构,可能迁移失败。 - 执行前建议做 DB 备份或快照。
- 若线上写流量较高,建议在低峰期执行并观察慢查询。