refs/refs/fhir-to-omop-demo/demo/translate/map/Observation.jq

205 lines · jq
2# Transforms FHIR Observations into OMOP table records.
5include "fhir";
6include "fhir/common";
9# An alias for the unit of the measurement.
10def unit:
11 .valueQuantity.concept
14def code_concept(domain):
15 (.code.coding[] | [select(.concept.domain_id == domain)]) as $concepts |
16 if ($concepts | length) > 1 then
17 error("Multiple \(domain) codings in Observation/\(.id) code: \($concepts)")
18 elif ($concepts | length) == 0 then
19 empty
20 else
21 $concepts[0].concept
22 end
25def condition: code_concept("Condition");
26def device: code_concept("Device");
27def drug: code_concept("Drug");
28def measurement: code_concept("Measurement");
29def procedure: code_concept("Procedure");
31def observation:
32 ["Condition", "Device", "Drug", "Measurement", "Procedure"] as $forbidden |
33 (
34 .code.coding[]
35 | [select(.concept.domain_id | IN($forbidden[]) | not)]
36 ) as $concepts |
37 if ($concepts | length) > 1 then
38 error("Multiple observation codings in Observation/\(.id) code")
39 elif ($concepts | length) == 0 then
40 empty
41 else
42 $concepts[0].concept
43 end
47# HACK: the coherent data set is missing codes for DNA observations, which
48# should be considered laboratory tests. This inserts a laboratory
49# code for any observation category that doesn't have a code.
50.category |= map(
51 .coding |= map(
52 if has("code") | not then . + {"code": "laboratory"} else . end
53 )
54) |
56Observation |
58 "condition_occurrence", # TABLE COLUMNS
59 .id, # condition_occurrence_id
60 .subject.id, # person_id
61 condition.concept_id, # condition_concept_id
62 .effectiveDateTime, # condition_start_date
63 .effectiveDateTime, # condition_start_datetime
64 .effectiveDateTime, # condition_end_date
65 .effectiveDateTime, # condition_end_datetime
66 32817, # condition_type_concept_id - source EHR
67 null, # condition_status_concept_id
68 null, # stop_reason
69 null, # provider_id - filled in by Encounter
70 .encounter.id, # visit_occurrence_id
71 null, # visit_detail_id - filled in by Encounter
72 condition.concept_code, # condition_source_value
73 condition.source_concept_id, # condition_source_concept_id
74 null # TODO: pick the best field for this.
75],
77 "device_exposure", # TABLE COLUMNS
78 .id, # device_exposure_id
79 .subject.id, # person_id
80 device.concept_id, # device_concept_id
81 .effectiveDateTime, # device_exposure_start_date
82 .effectiveDateTime, # device_exposure_start_datetime
83 .effectiveDateTime, # device_exposure_end_date
84 .effectiveDateTime, # device_exposure_end_datetime
85 32817, # device_type_concept_id - source EHR
86 null, # unique_device_id
87 null, # production_id
88 null, # quantity
89 null, # provider_id - filled in by Encounter
90 .encounter.id, # visit_occurrence_id
91 null, # visit_detail_id - filled in by Encounter
92 device.concept_code, # device_source_value
93 device.source_concept_id, # device_source_concept_id
94 null, # unit_concept_id
95 null, # unit_source_value
96 null # unit_source_concept_id
97],
99 "drug_exposure", # TABLE COLUMNS
100 .id, # drug_exposure_id
101 .subject.id, # person_id
102 drug.concept_id, # drug_concept_id
103 .effectiveDateTime, # drug_exposure_start_date
104 .effectiveDateTime, # drug_exposure_start_datetime
105 .effectiveDateTime, # drug_exposure_end_date
106 .effectiveDateTime, # drug_exposure_end_datetime
107 null, # verbatim_end_date
108 32817, # drug_type_concept_id - source EHR
109 null, # stop_reason
110 null, # refills
111 null, # quantity
112 null, # days_supply
113 null, # sig
114 null, # route_concept_id
115 null, # lot_number
116 null, # provider_id - filled in by Encounter
117 .encounter.id, # visit_occurrence_id
118 null, # visit_detail_id - filled in by Encounter
119 drug.concept_code, # drug_source_value
120 drug.source_concept_id, # drug_source_concept_id
121 null, # route_source_value
122 null # dose_unit_source_value
123],
125 "measurement", # TABLE COLUMNS
126 .id, # measurement_id
127 .subject.id, # person_id
128 measurement.concept_id, # measurement_concept_id
129 .effectiveDateTime, # measurement_date
130 .effectiveDateTime, # measurement_datetime
131 null, # measurement_time
132 32817, # measurement_type_concept_id - source EHR
133 null, # operator_concept_id
134 .valueQuantity.value, # value_as_number
135 null, # value_as_concept_id
136 unit.concept_id, # unit_concept_id
137 null, # range_low
138 null, # range_high
139 null, # provider_id - filled in by Encounter
140 .encounter.id, # visit_occurrence_id
141 null, # visit_detail_id - filled in by Encounter
142 measurement.concept_code, # measurement_source_value
143 measurement.source_concept_id, # source_concept_id
144 .valueQuantity.code, # unit_source_value
145 unit.source_concept_id, # unit_source_concept_id
146 null, # value_source_value
147 .encounter.id, # measurement_event_id
148 null # meas_event_field_concept_id
149],
150 # This CAN'T be condition, procedure, drug measurement, or device domains.
152 "observation", # TABLE COLUMNS
153 .id, # observation_id
154 .subject.id, # person_id
155 observation.concept_id, # observation_concept_id
156 .effectiveDateTime, # observation_date
157 .effectiveDateTime, # observation_datetime
158 32817, # observation_type_concept_id - source EHR
159 .valueQuantity.value, # value_as_number
160 .valueString, # value_as_string
161 null, # value_as_concept_id
162 null, # qualifier_concept_id
163 unit.concept_id, # unit_concept_id
164 null, # provider_id - See Encounter!
165 .encounter.id, # visit_occurrence_id
166 null, # visit_detail_id - see Encounter!
167 observation.concept_code, # observation_source_value
168 observation.concept_id, # observation_source_concept_id
169 .valueQuantity.unit, # unit_source_value
170 null, # qualifier_source_value
171 .valueQuantity.value, # value_source_value
172 .encounter.id, # observation_event_id
173 null # obs_event_field_concept_id
174],
176 "procedure_occurrence", # TABLE COLUMNS
177 .id, # procedure_occurrence_id
178 .subject.id, # person_id
179 procedure.concept_id, # procedure_concept_id
180 .effectiveDateTime, # procedure_date
181 .effectiveDateTime, # procedure_datetime
182 .effectiveDateTime, # procedure_end_date
183 .effectiveDateTime, # procedure_end_datetime
184 32817, # procedure_type_concept_id - source EHR
185 null, # modifier_concept_id
186 1, # quantity
187 null, # provider_id - filled in by Encounter
188 .encounter.id, # visit_occurrence_id
189 null, # visit_detail_id - filled in by Encounter
190 procedure.concept_code, # procedure_source_value
191 procedure.source_concept_id, # procedure_source_concept_id
192 null # modifier_source_value
194# Filter out Observations that don't have the expected number of fields.
195| select(
196 ((.[0] == "condition_occurrence") and length == 17) or
197 ((.[0] == "device_exposure") and length == 20) or
198 ((.[0] == "drug_exposure") and length == 24) or
199 ((.[0] == "measurement") and length == 24) or
200 ((.[0] == "observation") and length == 22) or
201 ((.[0] == "procedure_occurrence") and length == 17)
204@tsv