Observation
→
measurement
implemented
primary
Labs and vitals with numeric/coded results. Domain routing based on Observation.category: laboratory and vital-signs route here. Observations with components (e.g. blood pressure) are expanded -- each component produces its own measurement row.
Conversion profile
omop-observation-measurement
A FHIR instance converts to measurement iff it validates against this profile.
| Path | Card | Type | Binding / Fixed | Comment |
|---|---|---|---|---|
| Observation.status | fhir/observation-statusrequired | OMOP measurement requires a finalized value. | ||
| Observation.code | 1..*MS | omop-measurement-codesrequired | ||
| Observation.subject | 1..* | Reference | Required for measurement.person_id. | |
| Observation.effective[x] | 1..*MS | Required for measurement.measurement_date / measurement_datetime. | ||
| Observation.value[x] | 1..* | Quantity|CodeableConcept|string|boolean|integer | Required for measurement.value_as_number / value_as_concept_id / value_source_value. | |
| Observation.valueQuantity.unit | ||||
| Observation.valueQuantity.system | fixed: http://unitsofmeasure.org | Units must be UCUM for measurement.unit_concept_id resolution. |
ViewDefinition (Stage 1 flattener)
omop-observation-measurement
19 columns · resource Observation
| column name | FHIRPath | type |
|---|---|---|
| id | Observation.id | id |
| code_loinc | Observation.code.coding.where(system='http://loinc.org').first().code | code |
| code_snomed | Observation.code.coding.where(system='http://snomed.info/sct').first().code | code |
| code_text | Observation.code.text | string |
| value_code_snomed | Observation.valueCodeableConcept.coding.where(system='http://snomed.info/sct').first().code | code |
| value_code_loinc | Observation.valueCodeableConcept.coding.where(system='http://loinc.org').first().code | code |
| value_code_text | Observation.valueCodeableConcept.text | string |
| subject_id | Observation.subject | Reference(Patient) |
| measurement_date | Observation.effectiveDateTime | dateTime |
| measurement_datetime | Observation.effectiveDateTime | dateTime |
| operator | Observation.valueQuantity.comparator | code |
| value_as_number | Observation.valueQuantity.value | decimal |
| unit_text | Observation.valueQuantity.unit | string |
| unit | Observation.valueQuantity.code | code |
| range_low | Observation.referenceRange[0].low.value | decimal |
| range_high | Observation.referenceRange[0].high.value | decimal |
| performer_id | Observation.performer[0] | Reference(Practitioner) |
| encounter_id | Observation.encounter | Reference(Encounter) |
| value_text | Observation.valueQuantity | string |
Condition: category is laboratory or vital-signs (or absent/unknown -- default)
Implementation:
src/mapper/observation.tsFields (20)
-
measurement_id←Observation.idinteger · idPKrequiredGenerated deterministically from Observation.id. For component rows, suffixed with -comp-N (e.g. Observation.id + '-comp-0'). -
person_id←Observation.subjectinteger · Reference(Patient)FK→PERSONrequiredResolved from Observation.subject reference to Patient. -
measurement_concept_id←Observation.code | Observation.component.codeinteger · CodeableConceptFK→CONCEPTrequiredLOINC/SNOMED mapped to OMOP standard concept. For component rows, uses component.code instead of top-level code. Placeholder: 0 when concept lookup unavailable.2 sources ▾
-
LOINC priority vocab lookup; 0 when not found
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopObservation.java:863-1109 — constructOmopMeasurement
- fhir-omop-ig(fml) refs/refs/fhir-omop-ig/input/maps/Measurement.fml
-
Domain-based routing: LOINC code looked up in OMOP vocabulary for domain_id before mapping concept
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ObservationMapper.java:542-605 — LoincStandardDomainLookup drives routing and concept resolution
- fhir-to-omop-demo(jq) refs/refs/fhir-to-omop-demo/demo/translate/map/Observation.jq:14-23 — domain-based routing via pre-joined vocabulary
-
-
measurement_date←Observation.effectiveDateTime | Observation.effectivePeriod.startdate · dateTimerequiredFalls back to effectivePeriod.start when effectiveDateTime is absent. Observation is skipped if neither is available.3 sources ▾
-
effectivePeriod.start fallback; skip when both absent
- fhir-omop-ig(fml) refs/refs/fhir-omop-ig/input/maps/Measurement.fml:30-32 — dateTime, instant, Period.start
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ObservationMapper.java:279-291 — effectivePeriod fallback
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopObservation.java:1058-1071 — effectiveDateTime / Period; falls back to Date(0) not skip
-
issued used as date fallback when effectiveDateTime absent
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ObservationMapper.java:273-276 — issued fallback
-
effectiveInstant also mapped (not handled by this project or most others)
- fhir-omop-ig(fml) refs/refs/fhir-omop-ig/input/maps/Measurement.fml:29-29 — line 29 handles effectiveInstant
-
-
measurement_datetime←Observation.effectiveDateTime | Observation.effectivePeriod.startdatetime · dateTime -
measurement_type_concept_id← constant integerFK→CONCEPTrequiredmap:measurement_type=3281732817 = 'EHR'. Indicates the provenance of the measurement record.2 sources ▾
-
32817 (EHR) constant for all FHIR→OMOP measurement rows
- fhir-omop-ig(fml) refs/refs/fhir-omop-ig/input/maps/Measurement.fml
- FhirToCdm(csharp) refs/refs/FhirToCdm/FhirToCdmMappings.cs:482-558 — CreateMeasurement()
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ObservationMapper.java
-
Category-sensitive type concept: laboratory→44818702, exam→44818701, survey→45905771 (OMOP→FHIR direction)
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopObservation.java:1080-1104 — Category → type concept mapping
-
-
operator_concept_id←Observation.valueQuantity.comparator | Observation.component.valueQuantity.comparatorinteger · codeFK→CONCEPTmap:operator< -> 4171756, <= -> 4171754, >= -> 4171755, > -> 4172703. Null when comparator is absent. -
value_as_number←Observation.valueQuantity.value | Observation.component.valueQuantity.valuefloat · decimalNumeric result value from valueQuantity. For component rows, uses component.valueQuantity.value. -
value_as_concept_id←Observation.valueCodeableConcept | Observation.component.valueCodeableConceptinteger · CodeableConceptFK→CONCEPTRequires vocabulary lookup to map coded result to OMOP concept. Placeholder: null when lookup unavailable.2 sources ▾
-
Full vocabulary lookup to resolve coded result to OMOP standard concept
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopObservation.java:963-990 — valueCodeableConcept mapping with vocab lookup
- FhirToCdm(csharp) refs/refs/FhirToCdm/FhirToCdmMappings.cs:538-547 — ValueCodeableConcept lookup
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ObservationMapper.java:1474-1517 — setValueCodeableConceptInMeasurement
-
Passthrough of coding[0] without vocabulary lookup (interpretation → value_as_concept_id)
- fhir-omop-ig(fml) refs/refs/fhir-omop-ig/input/maps/Measurement.fml:44-50 — valueCodeableConcept + interpretation lines
-
-
unit_source_value←Observation.valueQuantity.unit | Observation.component.valueQuantity.unitvarchar(50) · stringHuman-readable unit string from the FHIR Quantity. -
unit_concept_id←Observation.valueQuantity.code | Observation.component.valueQuantity.codeinteger · codeFK→CONCEPTUCUM unit code mapped to OMOP unit concept. Placeholder: null when lookup unavailable.2 sources ▾
-
UCUM → OMOP vocabulary lookup performed at runtime
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopObservation.java:932-961 — Unit concept lookup from UCUM vocab; fallback from reference range if valueQuantity.unit absent (lines 1013-1055)
- FhirToCdm(csharp) refs/refs/FhirToCdm/FhirToCdmMappings.cs:526-531 — Unit lookup
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ObservationMapper.java
- fhir-to-omop-demo(jq) refs/refs/fhir-to-omop-demo/demo/translate/map/Observation.jq — pre-joined vocabulary lookup
-
null constant — no UCUM lookup performed
- fhir-omop-ig(fml) refs/refs/fhir-omop-ig/input/maps/Measurement.fml — unit concept not mapped in FML
-
-
range_low←Observation.referenceRange[0].low.valuefloat · decimalLower bound of the first reference range. Only the first referenceRange entry is used. -
range_high←Observation.referenceRange[0].high.valuefloat · decimalUpper bound of the first reference range. Only the first referenceRange entry is used. -
provider_id←Observation.performer[0]integer · Reference(Practitioner)FK→PROVIDERFirst performer reference resolved to provider_id. -
visit_occurrence_id←Observation.encounterinteger · Reference(Encounter)FK→VISIT_OCCURRENCEResolved from Observation.encounter reference. -
visit_detail_id← — integerFK→VISIT_DETAILNot mapped. No direct FHIR equivalent.1 source ▾
-
visit_detail_id set to same value as visit_occurrence_id
- FhirToCdm(csharp) refs/refs/FhirToCdm/FhirToCdmMappings.cs:517-518 — visit_detail_id = visit_occurrence_id
-
-
measurement_source_value←Observation.code.coding[best].code | Observation.component.code.coding[best].codevarchar(50) · codeBest code by vocabulary priority: LOINC > SNOMED > first available coding.3 sources ▾
-
Best vocabulary priority (LOINC > SNOMED > first coding code)
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ObservationMapper.java — LOINC code used
-
issued or note text used instead of code
- fhir-omop-ig(fml) refs/refs/fhir-omop-ig/input/maps/Measurement.fml — issued or note → measurement_source_value per Implementation Comparison
-
identifier.value used as source value
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopObservation.java:863-1109 — identifier.value per Implementation Comparison
-
-
measurement_source_concept_id← constant integer=0 -
unit_source_concept_id← constant integer=0 -
value_source_value←Observation.valueQuantity | Observation.valueString | Observation.valueCodeableConcept.textvarchar(50) · stringtransform:concat(comparator, value, ' ', unit) | valueString | valueCodeableConcept.textComputed: for valueQuantity concatenates comparator+value+unit; for valueString uses the string directly; for valueCodeableConcept uses .text. For component rows, derived from component values.2 sources ▾
-
Composite string: comparator+value+unit (or valueString / CC text)
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopObservation.java — Quantity.value toString per Implementation Comparison
- FhirToCdm(csharp) refs/refs/FhirToCdm/FhirToCdmMappings.cs — ValueAsNumber toString per Implementation Comparison
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ObservationMapper.java:1529-1554 — setValueQuantityInMeasurement
-
valueString → known concept IDs ('detected'/'not detected') attempted before falling back to value_source_value
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopObservation.java:991-1003 — valueString → known concepts
-
Vocabularies
operator
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| < | Less than | 4171756 | Less than |
| <= | Less than or equal to | 4171754 | Less than or equal to |
| >= | Greater than or equal to | 4171755 | Greater than or equal to |
| > | Greater than | 4172703 | Greater than |
| (absent) | No operator | - | No operator |
measurement_type
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| EHR | EHR | 32817 | EHR |
vital_signs_loinc
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| 85354-9 | Blood pressure panel | - | Parent panel -- expanded via components |
| 8480-6 | Systolic blood pressure | 3004249 | Systolic blood pressure |
| 8462-4 | Diastolic blood pressure | 3012888 | Diastolic blood pressure |
| 8310-5 | Body temperature | 3020891 | Body temperature |
| 8867-4 | Heart rate | 3027018 | Heart rate |
| 9279-1 | Respiratory rate | 3024171 | Respiratory rate |
| 2708-6 | Oxygen saturation in Arterial blood | 3016502 | Oxygen saturation |
| 29463-7 | Body weight | 3013762 | Body weight |
| 8302-2 | Body height | 3036277 | Body height |
| 39156-5 | Body mass index (BMI) | 3038553 | Body mass index |
Edge Cases
Missing effectiveDateTime
Skip -- measurement_date is required.
effectivePeriod instead of dateTime
Use period.start.
valueString (no value_as_string in measurement)
Captured in value_source_value only. omoponfhir attempts to map known strings to concept IDs.
Components (e.g. blood pressure)
Each component produces its own measurement row with suffixed ID. Parent metadata (date, subject, encounter, performer) is inherited.
Status not in {final, amended, corrected}
Skip entire observation.
Missing code.coding
Skip entire observation.
LOINC code not in OMOP vocabulary
measurement_concept_id=0. Code preserved in measurement_source_value.
Multiple referenceRange entries
Only first range used.
valueBoolean, valueInteger, valueRange, valueRatio
Not mapped. Could be coerced to value_as_number or value_source_value.
Reference Implementations
- fhir-omop-ig(fml) refs/refs/fhir-omop-ig/input/maps/Measurement.fml — 53 lines
- omoponfhir(java) refs/refs/omoponfhir-omopv5-r4-mapping/src/main/java/edu/gatech/chai/omoponfhir/omopv5/r4/mapping/OmopObservation.java:1-2164
- FhirToCdm(csharp) refs/refs/FhirToCdm/FhirToCdmMappings.cs — CreateMeasurement() lines 482-558
- ETL-German-FHIR-Core(java) refs/refs/ETL-German-FHIR-Core/src/main/java/org/miracum/etl/fhirtoomop/mapper/ObservationMapper.java
- fhir-to-omop-demo(jq) refs/refs/fhir-to-omop-demo/demo/translate/map/Observation.jq — 203 lines