Immunization drug_exposure documented primary

One FHIR Immunization maps to one drug_exposure row. Immunizations are point-in-time events: start_date = end_date, no days_supply or refills. Records are distinguished from other drug exposures by drug_concept_id belonging to the CVX vocabulary. Only completed immunizations are mapped; entered-in-error and not-done are skipped.

Conversion profile omop-immunization-drug-exposure
A FHIR instance converts to drug_exposure iff it validates against this profile.
Path Card Type Binding / Fixed Comment
Immunization.status 1..*MS fixed: completed Only completed immunizations are converted. entered-in-error and not-done are skipped.
Immunization.vaccineCode 1..*MS omop-drug-codesrequired
Immunization.patient 1..1 Reference Required for drug_exposure.person_id.
Immunization.occurrence[x] 1..1MS Required for drug_exposure.drug_exposure_start_date / _end_date. Immunizations are point-in-time events: start_date = end_date.
ViewDefinition (Stage 1 flattener) omop-immunization-drug-exposure
19 columns · resource Immunization
column name FHIRPath type
id Immunization.id id
vaccine_cvx Immunization.vaccineCode.coding.where(system='http://hl7.org/fhir/sid/cvx').first().code code
vaccine_ndc Immunization.vaccineCode.coding.where(system='http://hl7.org/fhir/sid/ndc').first().code code
vaccine_rxnorm Immunization.vaccineCode.coding.where(system='http://www.nlm.nih.gov/research/umls/rxnorm').first().code code
vaccine_text Immunization.vaccineCode.text string
subject_id Immunization.patient Reference(Patient)
drug_exposure_start_date Immunization.occurrenceDateTime dateTime
drug_exposure_start_datetime Immunization.occurrenceDateTime dateTime
drug_exposure_end_date Immunization.occurrenceDateTime dateTime
drug_exposure_end_datetime Immunization.occurrenceDateTime dateTime
stop_reason Immunization.statusReason.text string
quantity Immunization.doseQuantity.value decimal
sig Immunization.note[*].text string
route Immunization.route CodeableConcept
route_text Immunization.route.coding[0].code code
lot_number Immunization.lotNumber string
performer_id Immunization.performer[0].actor Reference(Practitioner)
encounter_id Immunization.encounter Reference(Encounter)
dose_unit_text Immunization.doseQuantity.unit string
Condition: status = completed (skip entered-in-error and not-done)

Fields (23)

Vocabularies

drug_type

Source Display Concept ID Concept Name
EHR EHR (default) 32817 EHR
physician-administered Physician administered drug 38000179 Physician administered drug (identified from EHR problem list)
ehr-administration EHR administration record 32818 EHR administration record
self-reported Patient Self-Reported (primarySource = false) 44787730 Patient Self-Reported

route

Source Display Concept ID Concept Name
IM Intramuscular 4302612 Intramuscular route
SC Subcutaneous 4302357 Subcutaneous route
PO Oral / Per Oral 4132161 Oral
NASINHL Nasal Inhalation 4262914 Nasal route
IDINJ Intradermal 4156706 Intradermal route

vaccine_code

Source Display Concept ID Concept Name
CVX:08 Hep B, adolescent or pediatric - Lookup in OMOP concept table where vocabulary_id = 'CVX'
CVX:10 IPV - Lookup in OMOP concept table where vocabulary_id = 'CVX'
CVX:20 DTaP - Lookup in OMOP concept table where vocabulary_id = 'CVX'
CVX:33 Pneumococcal polysaccharide PPV23 - Lookup in OMOP concept table where vocabulary_id = 'CVX'
CVX:88 Influenza, unspecified formulation - Lookup in OMOP concept table where vocabulary_id = 'CVX'
CVX:115 Tdap - Lookup in OMOP concept table where vocabulary_id = 'CVX'
CVX:141 Influenza, seasonal, injectable - Lookup in OMOP concept table where vocabulary_id = 'CVX'
CVX:207 COVID-19, mRNA, LNP-S, PF, 100 mcg/0.5mL (Moderna) - Lookup in OMOP concept table where vocabulary_id = 'CVX'
CVX:208 COVID-19, mRNA, LNP-S, PF, 30 mcg/0.3mL (Pfizer-BioNTech) - Lookup in OMOP concept table where vocabulary_id = 'CVX'
CVX:212 COVID-19, viral vector, non-replicating, Ad26 (Janssen) - Lookup in OMOP concept table where vocabulary_id = 'CVX'

status_filter

Source Display Concept ID Concept Name
completed Completed - Map -- vaccination was administered
entered-in-error Entered in Error - Skip -- data quality issue
not-done Not Done - Skip (most implementations). omoponfhir writes with stop_reason.

Edge Cases

occurrenceString instead of occurrenceDateTime
Cannot map -- drug_exposure_start_date is NOT NULL. Skip the record and log a warning.
primarySource = false
Vaccine reported secondhand (patient self-report, school record). Consider using drug_type_concept_id = 44787730 (Patient Self-Reported) instead of the default.
Multiple performer entries
Take the first performer[].actor for provider_id. Only one provider can be stored per drug_exposure row.
Vaccine series tracking (protocolApplied)
Not mapped. protocolApplied.doseNumber, seriesDoses, targetDisease have no OMOP equivalent.
reaction present
Not mapped to drug_exposure. Could create a separate observation row for adverse reactions, but no implementation does this for Immunization.
Missing vaccineCode
Skip the record. All implementations require a vaccine code.
Multiple vaccineCode.coding[] entries
Iterate codings to find one in a recognized vocabulary. ETL-German prefers ATC over SNOMED. omoponfhir takes the first coding that resolves.
SNOMED compound codes (+ separator)
ETL-German splits compound SNOMED codes on '+' and processes each sub-code separately, potentially creating multiple drug_exposure rows.
lotNumber exceeds 50 characters
Truncate to varchar(50). Rare in practice but possible with extended lot identifiers.
site (body site) present
No standard mapping to drug_exposure. Could map to route_source_value but this conflates route and site. Best practice: discard.
manufacturer present
No standard mapping. Could store in drug_source_value alongside the code, but no implementation does this.
expirationDate present
No OMOP target. Lost in translation.
note[].text present
omoponfhir concatenates notes into sig field. Not standard practice -- sig is intended for prescriber instructions.
Domain routing: concept maps to Observation domain
ETL-German checks concept.domain_id; if 'Observation' instead of 'Drug', routes to observation table instead of drug_exposure. Uncommon for CVX codes but possible with certain SNOMED vaccine concepts.
status = entered-in-error
Skip entirely. Data quality issue -- should not enter OMOP.
status = not-done
Most implementations skip. omoponfhir writes the record with stop_reason from statusReason.

Reference Implementations