Skip to content

Stage 3: FHIR resource extraction

Stage 3 reads FHIR R4 data into the same record tables as C-CDA documents, so a person's records from every health system and format sit side by side.

File shapes

A FHIR file can be a Bundle, a single resource, or NDJSON with one resource per line. Single resources and NDJSON are read as if they were a Bundle.

Resources read

Resource Bundle table Notes
Patient patients Name, birth date, sex, race and ethnicity (US Core extensions), MRN, the health system's patient ID as source_patient_id, and deceasedDateTime
Condition problems Every coding; onset and recorded dates; clinical status
Observation labs, vitals (and labs_vitals) Numeric, integer, text, coded and true or false values; units; category. Vital-sign observations go to vitals
MedicationRequest, MedicationDispense, MedicationAdministration, MedicationStatement medications fhir_resource_type is kept, so an order can be told from a dispense, an administration or reported use
Procedure procedures Performed date
Encounter encounters Class and type
DiagnosticReport diagnostic_reports Code, date and conclusion; attached report text becomes a document
DocumentReference document_references Attached text becomes a document
Binary documents Decoded content becomes a document
AllergyIntolerance, Immunization, CarePlan, Goal their own tables

Resources that do not belong to one patient, such as Practitioner, Organization and Location, are not read.

Choosing a code from several codings

A FHIR CodeableConcept can hold several codings for one thing, for example RxNorm and NDC for a medicine, or SNOMED CT and ICD-10-CM for a problem. fhir_prioritize_coding picks the code shown in code by domain:

Domain Preferred code systems, in order
Medication RxNorm
Problem SNOMED CT, then ICD-10-CM
Laboratory result and vital sign LOINC
Procedure CPT, then SNOMED CT
Allergy RxNorm, then SNOMED CT
Immunization CVX
Encounter CPT, then SNOMED CT

Every coding is kept in all_codings, and the add-on modules search all of them. C-CDA <code> elements are read the same way through extract_all_codings, which includes every <translation>, so an NDC code with an RxNorm translation is shown as RxNorm.

References across files

Exports often put a Medication resource in a different file from the MedicationRequest that points to it. Before the main pass, the pipeline reads every file once to index each Medication and each DocumentReference subject, so a medicationReference resolves wherever the Medication sits. On the warehouse route, a document listed in uuid_mapping.csv keeps the patient that file names; the DocumentReference index fills in only documents the mapping does not list.

Text attached to resources

Neurology notes, pulmonary function reports, genetic test reports and other documents are often delivered inside DiagnosticReport (presentedForm), DocumentReference (content) or Binary resources. Each attachment is decoded and converted by format (PDF, RTF, HTML or text) into a document with its own ID, title and date, and note extraction reads it like any other document. An attachment given only as a URL is not fetched; it is listed with the format external_attachment_not_retrieved so the gap is visible.

Deaths

Patient.deceasedDateTime is kept as deceased_date_time. The drug repurposing, cohort summary, OMOP and Phenopacket modules use it, together with any deaths in vital_status.csv.

Malformed resources

Exports sometimes hold malformed entries: strings where objects are expected, missing fields or encoding damage. Each file is parsed inside its own error handler, so one bad file is logged with its name and the error type and the run continues. Resources without a patient are skipped rather than written without one. Check the log for parse errors after each run.