Files
huike-back/docs/course-domain-jsonb-migration-runbook.md
T

207 lines
5.4 KiB
Markdown
Raw Normal View 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_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 权限:
```sql
\c htyws_local
SELECT current_user, current_database();
```
`htykc_local` 同样检查。
### 3.2 迁移前数据基线(建议保存结果)
`htyws_local`
```sql
-- 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`
```sql
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
```bash
cd huike-back/htyws_models
DATABASE_URL=postgres://htyws@localhost/htyws_local diesel migration run
```
### 4.2 执行 `htykc_models` migration
```bash
cd huike-back/htykc_models
DATABASE_URL=postgres://htykc@localhost/htykc_local diesel migration run
```
> 若本地无 `htykc` DB 角色,先创建角色或使用可用 DB 用户连接串再执行。
## 5. 迁移后校验
### 5.1 校验旧键已清理
`htyws_local``htykc_local` 分别执行:
```sql
-- 应返回 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` 可单独查:
```sql
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 校验新键可读
```sql
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 键名,可执行:
```bash
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 备份或快照。
- 若线上写流量较高,建议在低峰期执行并观察慢查询。