This page is part of the Vulcan FHIR to OMOP FHIR Implementation Guide (v1.0.0-ballot: INFORMATIVE 1 Ballot 1) based on FHIR (HL7® FHIR® Standard) v5.0.0. No current official version has been published yet. For a full list of available versions, see the Directory of published versions
Official URL: http://hl7.org/fhir/uv/omop/StructureMap/ConditionMap | Version: 1.0.0-ballot | |||
Standards status: Informative | Maturity Level: 1 | Computable Name: ConditionMap |
This mapping maps FHIR Condition instances to OMOP Condition Occurence Table objects.
Please note: a Condition use case is provided in the Free Text in CodeableConcept code mapping pattern section of this IG.
When implementing FHIR-to-OMOP transformations, two temporal concepts require careful consideration due to their distinct semantic meanings and downstream impact to analyses. Understanding these differences is crucial for implementers working on interoperability projects and clinical data warehousing initiatives.
The condition start date represents the clinically determined onset of the condition and forms the foundation of temporal analysis in clinical research. In FHIR implementations, this information is primarily sourced from Condition.onsetDateTime or Condition.onsetPeriod fields. When these explicit onset fields are unavailable, ETL developers often need to implement fallback logic that examines Condition.assertedDate or extract temporal information from clinical notes through natural language processing or manual extraction processes. This temporal marker maps directly to CONDITION_OCCURRENCE.condition_start_date in the OMOP Common Data Model. The clinical significance of this field cannot be overstated, as it serves as the cornerstone for temporal analyses, disease progression modeling, and epidemiological cohort studies where clinical timeline accuracy is paramount for valid research outcomes.
In contrast to the clinical onset, the recorded date captures when the condition was actually documented in the source system. This administrative timestamp reflects the healthcare workflow and documentation practices rather than the clinical reality of disease onset. In FHIR resources, this information is typically found in Condition.recordedDate, though the availability of this field varies significantly across different EHR implementations and vendor configurations. The challenge for implementers lies in the fact that the OMOP CDM lacks a native equivalent field for recorded dates. This architectural decision reflects OMOP's focus on clinical events rather than administrative metadata. However, several implementation strategies can address this gap, including the development of custom extensions within the CONDITION_OCCURRENCE table, creation of dedicated metadata tables for comprehensive provenance tracking, utilization of the NOTE table with structured content, or establishing separate ETL audit tables that maintain this temporal information alongside the clinical data.
It is a global challenge mapping FHIR to OMOP that OMOP's clinical-event focus prioritizes onset information over administrative timestamps. This philosophical difference requires architects and implementers to make deliberate decisions about how to preserve recorded date information when audit requirements or analytical needs demand such provenance tracking. Missing data scenarios present particular complexity for ETL developers. When onsetDateTime is unavailable in the source FHIR data, the temptation exists to use recordedDate as a proxy for clinical onset. While this approach may seem pragmatic, it introduces analytical bias that can significantly impact downstream research and clinical decision-making. Such substitutions must be thoroughly documented in ETL metadata and clearly communicated to end users.
Temporal discrepancies between onset and documentation dates might reveal interesting patterns in healthcare delivery and documentation practices. Significant lags between when a condition clinically manifests and when it gets recorded in the EHR can affect different use cases in distinct ways, with clinical analyses requiring accurate onset timing while operational assessments may depend more heavily on documentation patterns. It is important for implementers to understand the differences in source date data context, and provide documentation regarding decisions made for each individual data source feeding an OMOP instance.
condition_type_concept_id
Date type | Best suited for | Focus |
---|---|---|
Onset (condition start) date | Clinical-research studies, outcomes analyses, temporal cohort definitions | Reflecting biological and clinical reality |
Recorded (entry) date | Data-governance metrics, ETL validation, documentation-pattern reviews, regulatory-compliance audits | Understanding and optimizing operational processes |
/// url = 'http://hl7.org/fhir/uv/omop/StructureMap/ConditionMap' /// name = 'ConditionMap' /// title = 'Mapping Condition resource to Condition Occurrence OMOP Domain' /// status = 'draft' uses "http://hl7.org/fhir/StructureDefinition/Condition" alias Condition as source uses "http://hl7.org/fhir/uv/omop/StructureDefinition/ConditionOccurrence" alias ConOccTable as target group ConditionOccurrence(source src : Condition, target tgt : ConOccTable) { src.code as s -> tgt then { s.coding as sc -> tgt then { sc.code as a -> tgt.condition_concept_id = a; }; }; // src.id as id -> tgt.condition_occurrence_id = cast(id, "integer"); src.recordedDate as rd -> tgt.condition_start_datetime = cast(rd, 'dateTime'), tgt.condition_start_date = rd; src.onset : dateTime as osd -> tgt.condition_start_datetime = osd, tgt.condition_start_date = cast(osd, 'date'); src.abatement : dateTime as abdt -> tgt.condition_end_datetime = adt, tgt.condition_end_date = cast(abdt, 'date'); src.category as s -> tgt then { s.coding as sc -> tgt then { sc.code as a -> tgt.condition_type_concept_id = a; }; }; src.clinicalStatus as s -> tgt then { s.coding as sc -> tgt then { sc.code as a -> tgt.condition_status_concept_id = a; }; }; src.evidence as s -> tgt then { s.concept as sc -> tgt then { sc.coding as sci -> tgt then { sci.code as a -> tgt.condition_source_concept_id = a; }; }; }; // src.encounter as s -> tgt then { }