- 분야: DB
- 기술 스택: Node.js · SQLite · 콘텐츠 내보내기
문제와 원인
원본 DB의 변형 문항은 variant_group_id로 연결돼 있었지만 내보내기 결과에는 이 컬럼이 빠졌다. SELECT 목록을 만드는 QUESTION_COLUMNS에 해당 필드가 없었기 때문이다.
문항 행 수는 5,225개로 유지돼 개수 검사만으로는 누락을 찾기 어려웠다. 그룹 ID가 있는 28개 문항을 ID별로 대조하자 모두 관계 필드가 빠져 있었다.
수정 전 코드
QUESTION_COLUMNS
그룹 ID가 빠진 컬럼 목록으로 문항을 내보냈다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
export const QUESTION_COLUMNS = Object.freeze([
"id", "category", "topic", "display_order", "exam_scope", "difficulty",
"difficulty_rationale", "kind", "prompt", "choices", "correct_answers",
"explanation", "tags", "scoring_criteria", "required_concepts",
"acceptable_alternatives", "deduction_conditions", "error_conditions",
"theory_id", "practice_scope", "bookmarked", "active", "created_at", "updated_at",
]);
readCanonicalContent
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
const questions = database.prepare(`
SELECT ${QUESTION_COLUMNS.join(", ")}
FROM questions
ORDER BY display_order, id
`).all();
수정 후 코드
QUESTION_COLUMNS
이전 컬럼 목록을 LEGACY_QUESTION_COLUMNS로 보존하고 content-v2의 목록에 variant_group_id를 추가했다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
export const LEGACY_CONTENT_SCHEMA_VERSION = "content-v1";
export const CONTENT_SCHEMA_VERSION = "content-v2";
export const QUESTION_COLUMNS = Object.freeze([
...LEGACY_QUESTION_COLUMNS.slice(0, 20),
"variant_group_id",
...LEGACY_QUESTION_COLUMNS.slice(20),
]);
questionColumnsForSchema
조회에서는 스키마 버전에 맞는 목록을 선택한다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
function questionColumnsForSchema(schemaVersion) {
if (schemaVersion === LEGACY_CONTENT_SCHEMA_VERSION) {
return LEGACY_QUESTION_COLUMNS;
}
if (schemaVersion === CONTENT_SCHEMA_VERSION) {
return QUESTION_COLUMNS;
}
throw new Error(`unsupported content schema: ${schemaVersion}`);
}
readCanonicalContent
선택한 스키마의 컬럼 목록으로 조회한다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
const questionColumns = questionColumnsForSchema(schemaVersion);
const questions = database.prepare(`
SELECT ${questionColumns.join(", ")}
FROM questions
ORDER BY display_order, id
`).all();
검증 결과
같은 DB의 내보내기 비교
Node.js, SQLite에서 같은 기준 DB로 수정 전후 readCanonicalContent()를 실행했다. 원본의 문항 ID별 그룹 값과 결과를 대조하고, 내보낸 레코드를 Wrangler의 로컬 D1에 적재해 Local Explorer SQL로 조회했다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
| 비교 항목 | 수정 전 | 수정 후 |
|---|---|---|
| 내보낸 문항 | 5,225개 | 5,225개 |
| 내보낸 이론 | 158개 | 158개 |
| 그룹 ID가 있는 28개 문항의 값 보존 | 0/28개 | 28/28개 |
variant_group_id 필드를 포함한 문항 | 0개 | 5,225개 |
| 그룹 ID 외의 문항 필드 전체 값 | 기준값 | 모두 일치 |
| 이론 필드 전체 값 | 기준값 | 모두 일치 |
content-v1 조회 결과 | 기준값 | 모두 일치 |
그룹 값이 없는 나머지 5,197개 문항은 null을 유지했다. 기존 필드 비교는 새 그룹 ID 필드를 제외하고 전체 컬럼을 직렬화해 수행했다.