FHIR Store Mappings

From Discovery Data Service
Revision as of 10:05, 25 April 2022 by JoshuA (talk | contribs) (→‎OBR - Observation Request)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

NM"Introduction

This page describes the mapping between the HL7v2 segments that DDS can ingest and the FHIR Resources (TODO link to profiles) that DDS uses to represent them internally.

There are two kinds ways that values are written into the internal FHIR store when mapping from an inbound HL7v2 message -

  1. Dynamic values - here the raw value from the inbound HL7v2 message is copied into a property on a FHIR resource
  2. Fixed values - here the value that is inserted into a FHIR resource is fixed and is not copied from the source message. Instead the value that is inserted is likely to be contingent on the presence and/or value of a field from the source message

The relationship between HL7v2 segments and the FHIR resources that they populate is also diagrammed in the Entity Relationship section.

Dynamic Values

PID - Patient Identification

Field Component Resource Property References Condition
PID:3 PID:3.1 Encounter patient Patient
PID:3 PID:3.1 EpisodeOfCare patient Patient
PID:3 PID:3.1 Patient identifier.value if PID:3.4 == "MRN" then set to PID:3.1
PID:3 PID:3.4 Patient identifier.system
PID:3 PID:3.1 Patient identifier.value if PID:3.4 == "NHS" then set to PID.3.1
PID:5 PID:5.1 Patient name.family
PID:5 PID:5.2 Patient name.given
PID:5 PID:5.3 Patient name.middle
PID:5 PID:5.5 Patient name.prefix
PID:7 PID:7.1 Patient birthDate
PID:8 PID:8.1 Patient gender
PID:11 PID:11.1 Patient address.line
PID:11 PID:11.2 Patient address.line
PID:11 PID:11.3 Patient address.city
PID:11 PID:11.5 Patient address.postalCode
PID:11 PID:11.6 Patient address.country
PID:11 PID:11.9 Patient address.district
PID:13 PID:13.1 Patient telecom.value
PID:13 PID:13.2 Patient telecom.use if PID:13.2 == 'PRS' then set to "mobile"

if PID:13.2 == 'PRN' then set to "home"

PID:13 PID:13.4 Patient telecom.value if PID:13.2 == 'NET' then set to PID:13.4
PID:14 PID:14.1 Patient telecom.value
PID:14 PID:14.4 Patient telecom.value if PID:14.2 == 'NET' then set to PID:14.4
PID:15 PID:15.1 Observation code.coding.code Patient if PID:15.1 is not empty then look up core concept from Information Model and insert into property
PID:15 PID:15.4 Observation code.coding.code Patient
PID:17 PID:17.1 Observation code.coding.code Patient if PID:17.1 is not empty then look up core concept from Information Model and insert into property
PID:18 PID:18.1 Encounter contained.Parameters.parameter.valueCodeableConcept.coding.code Patient
PID:22 PID:22.1 Patient http://endeavourhealth.org/fhir/StructureDefinition/primarycare-ethnic-category-extension
PID:29 PID:29.1 Patient deceased

PD1 - Patient Additional Demographic

Field Component Resource Property References Condition
PD1:3 PD1:3.1 Organization identifier.name
PD1:3 PD1:3.3 Organization identifier.value
PD1:3 PD1:3.3 Patient careProvider Organization
PD1:4 PD1:4.1 Patient careProvider Practitioner

PV1 - Patient Visit

Field Component Resource Property References Condition
PV1:2 PV1:2.1 Encounter class
PV1:3 PV1:3.9 Encounter location (current) Location
PV1:3 PV1:3.9 Location identifier
PV1:3 PV1:3.9 Location name
PV1:3 PV1:3.9 Location description
PV1:4 PV1:4.1 Encounter contained.Parameters.parameter.name if PV1:4 is not empty then set to "DM_methodOfAdmssion"
PV1:4 PV1:4.1 Encounter contained.Parameters.parameter.valueCodeableConcept.coding.code
PV1:6 PV1:6.9 Encounter location (prior) Location
PV1:6 PV1:6.9 Location identifier
PV1:7 PV1:7.1 Encounter participant (attending clinician) Practitioner
PV1:7 PV1:7.1 Practitioner identifier.value
PV1:7 Practitioner identifier.system if PV1:7 is not empty then set to ? (need to find a type system)
PV1:7 PV1:7.2 Practitioner name.family
PV1:7 PV1:7.3 Practitioner name.given
PV1:7 PV1:7.4 Practitioner name.given
PV1:7 PV1:7.6 Practitioner name.prefix
PV1:8 PV1:8.1 Encounter participant (consulting clinician) Practitioner
PV1:8 PV1:8.1 Practitioner identifier.value
PV1:8 PV1:8.2 Practitioner name.family
PV1:8 PV1:8.3 Practitioner name.given
PV1:8 PV1:8.4 Practitioner name.given
PV1:8 PV1:8.6 Practitioner name.prefix
PV1:9 PV1:9.1 EpisodeOfCare careManager
PV1:9 PV1:9.1 Encounter participant (referring clinician) Practitioner
PV1:9 PV1:9.1 Practitioner identifier.value
PV1:9 PV1:9.2 Practitioner name.family
PV1:9 PV1:9.3 Practitioner name.given
PV1:9 PV1:9.4 Practitioner name.given
PV1:9 PV1:9.6 Practitioner name.prefix
PV1:14 PV1:14.1 Encounter contained.Parameters.parameter.valueCodeableConcept.coding.code
PV1:18 PV1:18.1 Encounter type
PV1:19 PV1:19.1 Encounter episodeOfCare EpisodeOfCare
PV1:36 PV1:36.1 Encounter contained.Parameters.parameter.valueCodeableConcept.coding.code
PV1:37 PV1:37.1 Encounter contained.Parameters.parameter.valueCodeableConcept.coding.code
PV1:44 PV1:44.1 Encounter period.start
PV1:44 PV1:44.1 EpisodeOfCare startDt
PV1:45 PV1:45.1 Encounter period.end
PV1:45 PV1:45.1 EpisodeOfCare endDt

MSH - Message Header

Field Component Resource Property References Condition
MSH:3 MSH:3.1 EpisodeOfCare managingOrganization Organization
MSH:3 MSH:3.1 Organization identifier.name
MSH:3 MSH:3.3 Organization identifier.value
MSH:7 MSH:7.1 DiagnosticReport issued if MSH.9.1 == "R01"

AL1 - Patient Allergy Information

Field Component Resource Property References Condition
AL1:2 AL1:2.1 AllergyIntolerance category
AL1:3 AL1:3.1 AllergyIntolerance substance.coding.code
AL1:3 AL1:3.2 AllergyIntolerance substance.coding.display
AL1:3 AL1:3.3 AllergyIntolerance substance.coding.system
AL1:4 AL1:4.1 AllergyIntolerance reaction[].severity.code
AL1:5 AL1:5.1 AllergyIntolerance reaction[].manifestation.coding.code
AL1:5 AL1:5.2 AllergyIntolerance reaction[].manifestation.coding.display
AL1:5 AL1:5.3 AllergyIntolerance reaction[].manifestation.coding.system
AL1:6 AL1:6.1 AllergyIntolerance reaction[].onset

DG1 - Diagnosis

Field Component Resource Property References Condition
DG1:3 DG1:3.1 Condition substance.coding.code
DG1:3 DG1:3.2 Condition substance.coding.display
DG1:3 DG1:3.3 Condition substance.coding.system
DG1:4 DG1:4.1 Condition reaction[].severity.code
DG1:5 DG1:5.1 Condition reaction[].manifestation.coding.code
DG1:16 DG1:16.1 Condition asserter Practitioner
DG1:16 DG1:16.1 Practitioner identifier.value
DG1:16 DG1:16.2 Practitioner name.family
DG1:16 DG1:16.3 Practitioner name.given
DG1:16 DG1:16.4 Practitioner name.given
DG1:16 DG1:16.6 Practitioner name.prefix
DG1:17 DG1:17.1 Condition requires a new extension

PR1 - Procedures

Field Component Resource Property References Condition
PR1:3 PR1:3.1 Procedure code.coding.code
PR1:3 PR1:3.2 Procedure code.coding.display
PR1:3 PR1:3.3 Procedure code.coding.system
PR1:4 PR1:4.1 Procedure code.text
PR1:5 PR1:5.1 Procedure performedDateTime
PR1:6 PR1:6.1 Procedure category

NTE - Notes and Comments

Field Component Resource Property References Condition
NTE:3 NTE:3.1 Observation comments if MSH:3.1 == "RADIOLOGY" and this NTE segment immediately follows the last OBX segment under a parent OBR segment
NTE:3 NTE:3.1 Observation valueString if MSH:3.1 != "RADIOLOGY" and this NTE segment immediately follows the last OBX segment under a parent OBR segment

OBR - Observation Request

Field Component Resource Property References Condition
OBR:3 OBR:3.1 DiagnosticReport identifier.value
OBR:24 OBR:24.1 DiagnosticReport category.coding.system
OBR:4 OBR:4.1 DiagnosticReport code.coding.code
OBR:4 OBR:4.2 DiagnosticReport code.text
OBR:4 OBR:4.2 DiagnosticReport code.coding.display
OBR:7 OBR:7.1 DiagnosticReport effectiveDateTime
OBR:7 OBR:7.1 Observation effectiveDateTime Used if OBX:14.1 is not present
OBR:16 OBR:16.1 DiagnosticReport Diagnostic_Report_Filed_By Practitioner
OBR:16 OBR:16.1 Practitioner identifier.value
OBR:16 OBR:16.2 Practitioner name.family
OBR:16 OBR:16.3 Practitioner name.given
OBR:16 OBR:16.4 Practitioner name.given
OBR:16 OBR:16.6 Practitioner name.prefix

ORC - Common Order

Field Component Resource Property References Condition
ORC:21 ORC:21.3 DiagnosticReport orderingOrganization Organization
ORC:21 ORC:21.3 Observation performer Organization
ORC:21 ORC:21.3 Organization identifier.value if MSH:3.1 != "RADIOLOGY"
ORC:21 ORC:21.1 Organization name

Note: the data path described in the ORC mappings is aspirational and has not been implemented in the current DDS codebase. (DDS uses the Organisation listed in the context instead currently).

OBX - Observation or result

OBX data is mapped differently depending upon whether or not the data represents a pathology, microbiology or a radiology result (see ORU R01: Unsolicited Observation for more details on how that distinction should be made).

Regardless of the type of result there are some mappings that are common

Field Component Resource Property References Condition
OBX:1 OBX:1.1 Observation identifier.value OBR:3.1 + OBX.1.1 creates a composite identifier for the Observation
OBX:3 OBX:3.1 Observation code
OBX:8 OBX:8.1 Observation interpretation.coding.code
OBX:14 OBX:14.1 Observation effectiveDateTime Used in preference to OBR:7.1
OBX:16 OBX:16.1 Observation Diagnostic_Report_Filed_By Practitioner
OBX:16 OBX:16.1 Practitioner identifier.value
OBX:16 OBX:16.2 Practitioner name.family
OBX:16 OBX:16.3 Practitioner name.given
OBX:16 OBX:16.4 Practitioner name.given
OBX:16 OBX:16.6 Practitioner name.prefix
Pathology results

Pathology results are divided into two categories -

Single textual report

In the case of a single textual report all related OBX segments (see here for detail on how this report type is identified) are aggregated into the same FHIR Observation instance. The value of each OBX:5.1 field is appended to the valueString property of that same Observation instance. It is also worth noting that NTE segments the follow directly after the parent OBR segment will also be appended on to the valueString (see here for NTE mapping strategy).

Note that the DDS mapping logic will not attempt to insert any newline characters. Instead the Observation.valueString is simply built by concatenating the raw text in the order in which the OBX and NTE segments are encountered.

Field Component Resource Property References Condition
OBX:5 OBX:5.1 Observation valueString if OBX:2.1 == "ST"

OR if OBX:2.1 == "TX"

OR

if OBX:2.1 == "FT"

Collection of individual results

Where an OBX segment encapsulates a single result (see for here detail on how this report type is identified) then each OBX will have an equivalent FHIR Observation instance created

Field Component Resource Property References Condition
OBX:5 OBX:5.1 Observation valueQuantity if OBX:2.1 == "NM"
OBX:5 OBX:5.1 Observation valueQuantity.value if OBX:2.1 == "NM"
OBX:6 OBX:6.1 Observation valueQuantity.unit if OBX:2.1 == "NM"
OBX:6 OBX:6.1 Observation referenceRange.low.unit if OBX:2.1 == "NM"
OBX:6 OBX:6.1 Observation referenceRange.high.unit if OBX:2.1 == "NM"
OBX:7 OBX:7.1 Observation referenceRange.low.value if OBX:2.1 == "NM"

if OBX.7.1 matches the regex "([0-9a-zA-Z\.]+)-(.+)" take first capture group as value

OBX:7 OBX:7.1 Observation referenceRange.high.value if OBX:2.1 == "NM"

if OBX.7.1 matches the regex "([0-9a-zA-Z\.]+)-(.+)" take second capture group as value

Radiology results

A radiology result can contain one or multiple images. In each case the image(s) can be accompanied with a textual element.

  • Single image OBX - In this case the image data are mapped to a single FHIR Observation instance and the valueAttachment property holds the image
  • Multiple image OBX - In this case all individual image data are mapped to heir own component.valueAttachment instance that are all encapsulated within the same single Observation instance
  • Textual OBX (one or multiple) - All textual OBX (and also any NTE segments directly following the parent OBR segment) are concatenated on to the comments property of the Observation instance. Note that the DDS mapping logic will not attempt to insert any newline characters.

Where an OBX holds a a recognised image (see here for detail on supported image types) then it is mapped to a

Field Component Resource Property References Condition
OBX:5 OBX:5.1 Attachment data
OBX:5 OBX:5.3 Attachment contentType
Microbiology results

TODO

Fixed Values

PID - Patient Identification

Resource Property Value
Patient identifier.system if PID:3.4 == "NHS" then set to "https://fhir.hl7.org.uk/Id/nhs-number"
Patient address.use if PID:11.7 == 'TEMPORARY' then set to 'temp' else set to 'home'
Patient telecom.use set to "work"
Patient communication.preferred if PID:15.1 is not empty then set to "true"
Patient communication.preferred if PID:15.4 is not empty then set to "false"
Encounter contained.Parameters.parameter.name if PID:18 is not empty then set to "CM_PatientFIN"
Encounter contained.Parameters.parameter.valueCodeableConcept.coding.system if PID:18 is not empty then set to ? (need a code system here)

PD1 - Patient Additional Demographic

Resource Property Value
Organization identifier.system if PD1:3.3 is not empty then set to "http://fhir.nhs.net/Id/ods-organization-code"
Organization identifier.type if PD1:3.3 is not empty then set to "official"
Organization type.system if PD1:3.3 is not empty then set to "http://endeavourhealth.org/fhir/ValueSet/primarycare-organization-type"
Organization type.code if PD1:3.3 is not empty then set to "PR"
Organization type.display if PD1:3.3 is not empty then set to "GP Practices in England and Wales"

PV1 - Patient Visit

Resource Property Value
Location status if PV1:3.9 is not empty then set to "ACTIVE"
Encounter contained.Parameters.parameter.valueCodeableConcept.coding.system if PV1:4 is not empty then set to ? (need a code system here)
Location status if PV1:6.9 is not empty then set to "ACTIVE"
Practitioner identifier.system if PV1:8 is not empty then set to "http://endeavourhealth.org/fhir/Identifier/gmp-ppd-code"
Practitioner identifier.system if PV1:9 is not empty then set to "http://endeavourhealth.org/fhir/Identifier/gmp-ppd-code"
Encounter contained.Parameters.parameter.name if PV1:14 is not empty then set to "DM_sourceOfAdmission"
Encounter contained.Parameters.parameter.valueCodeableConcept.coding.system if PV1:14 is not empty then set to ? (need a code system here)
Encounter contained.Parameters.parameter.name if PV1:36 is not empty then set to "DM_dischargeMethod"
Encounter contained.Parameters.parameter.valueCodeableConcept.coding.system if PV1:36 is not empty then set to ? (need a code system here)
Encounter contained.Parameters.parameter.name if PV1:37 is not empty then set to "DM_destination"
Encounter contained.Parameters.parameter.valueCodeableConcept.coding.system if PV1:37 is not empty then set to ? (need a code system here)

MSH - Message Header

Resource Property Value
Organization identifier.system if MSH:3.3 is not empty then set to "http://fhir.nhs.net/Id/ods-organization-code"
Organization identifier.system if MSH:3.3 is not empty then set to "official"

DG1 - Diagnosis

Resource Property Value
Practitioner identifier.system if DG1:16.1 is not empty then set to TODO

ORC - Common Order

Resource Property Value
Organization identifier.system if ORC:23.1 is not empty then set to "http://fhir.nhs.net/Id/ods-site-code"

OBR - Observation Request

Resource Property Value
DiagnosticReport identifier.system if OBR:3.1 is not empty and if MSH.3.1 != "RADIOLOGY" then set to "https://fhir.hl7.org.uk/path/id/{MSH:4.1}"

if OBR:3.1 is not empty and if MSH.3.1 == "RADIOLOGY" then set to "https://fhir.hl7.org.uk/rad/id/{MSH:4.1}"

DiagnosticReport category.coding.system if OBR.24 is not empty then set to "http://hl7.org/fhir/v2/0074"

TODO - set a bespoke coding system for Radiology results

DiagnosticReport category.coding.code if MSH.3.1 == "RADIOLOGY" then set to "RAD"
DiagnosticReport identifier.system if OBR:3.1 is not empty and if MSH.3.1 != "RADIOLOGY" then set to TODO

if OBR:3.1 is not empty and if MSH.3.1 == "RADIOLOGY" then set to TODO

DiagnosticReport status if OBR:25 == "F" then set to "final"

if OBR:25 == "C" then set to "corrected"

Observation identifier.system if OBR:3.1 is not empty and if MSH.3.1 != "RADIOLOGY" then set to "https://fhir.hl7.org.uk/path/id/{MSH:4.1}"

if OBR:3.1 is not empty and if MSH.3.1 == "RADIOLOGY" then set to "https://fhir.hl7.org.uk/rad/id/{MSH:4.1}"

Observation category.coding.system if MSH.3.1 == "RADIOLOGY" then set to TODO

if MSH.3.1 != "RADIOLOGY" and then set to TODO

OBX - Observation or result

Resource Property Value
Observation component.code.coding.system if OBX:3.1 is not empty and if MSH.3.1 != "RADIOLOGY" then set to "TODO - UTL?"

if OBX:3.1 is not empty and if MSH.3.1 == "RADIOLOGY" then set to "TODO"

Observation component.interpretation.valueCodeableConcept.coding.system if OBX:3.1 is not empty then set to "http://hl7.org/fhir/ValueSet/observation-interpretation"
Observation status if OBX:11 == "F" then set to "final"

if OBX:11 == "C" then set to "corrected"

Entity Relationship

The section describes how the references between FHIR resources are created. It shows where the references are sourced from in the original HL7v2 messages. This section is presented as a series of diagrams each centered around a main FHIR resource. On the left are the source segments mapping into the main FHRI resource in the middle. On the right are the FHIR resources that those mappings then reference. Note that the origin on the data held within each FHIR resource is detailed in the tables above - this section is purely concerned with references between resources.

Encounter

Hl7 to fhir encounter3.png

Patient

Hl7 to fhir patient.png

AllergyIntolerance, Condition and Procedure

All three of AllergyIntolerance, Condition and Procedure reference the same resources and use the same HL7 fields to create the relationship

Hl7 to fhir allergy-condition-procedure2.png

EpisodeOfCare

Hl7 to fhir episodeofcare.png

DiagnosticReport

Hl7 to fhir diagnosticreport.png

Observation

Hl7 to fhir observation.png