JohnMoehrke PHR FHIR API
0.5.2 - ci-build
JohnMoehrke PHR FHIR API, published by John Moehrke (himself). This guide is not an authorized publication; it is the continuous build for version 0.5.2 built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/JohnMoehrke/phr/ and changes regularly. See the Directory of published versions
Page standards status: Informative |
This page includes an analysis of the Oracle Health (OH) FHIR support of the same health concepts delivered here from Vista. This section is based on sample data, Oracle Health FHIR documentation, and discussions with Oracle Health contacts.
The following tables have the following columns:
Where notes are more complex, especially those that would not fit nicely into the tables, there are sub sections with notes
Features that MHV provides today with Vista
When OH is added as a data feed. Where will duplicate data be detected and removed? OH does not provide clear provenance on the data they import from Vista.
This section contains any generalizable observations and concerns.
concept | Delta Impact | Vista/FHIR | OH/FHIR |
---|---|---|---|
DateTime | High | local date/time, with attempt at proper timezone of where recorded | always UTC, no timezone. Likely need to use Encounter / Location to divine the timezone |
Effective Period | low | Effective is always populated with EffectiveDateTime | is EffectivePeriod ever populated instead? |
References | High | Many resource references to contained resources | Most references are real. Thus will need to add _include to searches to get these in the same Bundle, or retrieve each individually. |
identifier | low | links to vista identifiers | does not link to vista identifier (on Import, all data are imported against a single Encounter created for the import act) |
station indication | High | All data are identifiable back to Vista location | One database, no VISN separation. Would tend to need to navigate thru the referenced Encounter |
Encounter | High | None | Encounter is very important to all data. Especially the location where the data was gathered |
CodeableConcept | medium | tend to be enough to use code.text, sometimes a code, sometimes a code from a formal codeSystem | may have a code.text, but likely need to look to code.coding.display. See Note 1 |
Note that some of the va.gov handling does do this processing this way. hence why I indicate it as medium impact.
Note 1: OH example
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "735971005",
"display": "Fish (substance)"
}
],
"text": "Fish"
},
A common data need our MHV / va.gov User Interface (UI) has is to show where the data was gathered. In Vista this is a field of the main datatype, where as in OH this would be found in a related Encounter.
With Vista data, we preserve any source (Vista) id values in the Resource.identifier.
With OH, they do not preserve the source (Vista) id values. They do however create an Encounter resource that stands for the data import act. Thus all data that was imported from Vista, will have the same Encounter. (Would like to get an example of this)
This presents a big problem with de-duplication, and will be a struggle for us to not show the patient the same data as maintained in original Vista and as replicated into OH.
MHV PHR | MHV FHIR | va.gov UI | FHIR us-core | OH FHIR | Note |
---|---|---|---|---|---|
id | id | id | id | ||
identifier | no identifier in examples | ||||
clinicalStatus is active | clinicalStatus | clinicalStatus may be active | |||
verificationStatus may be entered-in-error | verificationStatus | verificationStatus | use confirmed/unconfirmed rather than observedHistoric? | ||
type | |||||
Allergy Type | category (medication, food, environment) | type | category | ||
criticality | |||||
Allergen | code.text | name | code | code | See CodeableConcept note |
patient | patient | patient | |||
encounter | see Encounter / Location note | ||||
onset[x] | |||||
Date Entered | recordedDate | date | recordedDate | ||
recorder | |||||
recorder.extension[alternate-reference] | location | ||||
asserter | |||||
Comments | note.text | notes | notes | no example | |
note.time | no example | ||||
Reactions | reaction.manifestation.text | reaction | reaction.manifestation | reaction.manifestation.text | |
reaction.manifestation.code | reaction.manifestation.code | no example | |||
reaction.severity | |||||
Observed/Historic | extension[observedHistoric] | observedOrReported | NA | see verificationStatus? |
MHV PHR | MHV FHIR | va.gov UI | FHIR us-core | OH FHIR | Note |
---|---|---|---|---|---|
id | id | id | id | ||
extension[assertedDate] | |||||
id | identifier | ||||
status | clinicalStatus | clinicalStatus | clinicalStatus | ||
verified | verificationStatus | verificationStatus | verificationStatus | ||
problem-list-item |
category (problem-list-item) | category (problem-list-item, health-concern) | category (problem-list-item, encounter-diagnosis, health-concern) | includes more than just problems | |
severity | severity | ||||
type.name | code.text | name | code.text | code.text | See CodeableConcept note |
icd | code.coding (icd) | code.coding (sct) | code.coding (sct, icd) | ||
patient | subject (Patient) | subject (Patient) | subject (Patient) | ||
onsetDate | onsetDateTime | onset[x] | onsetDateTime | ||
abatementDateTime | abatementDateTime | abatement[x] | abatementDateTime | ||
timestamp | recordedDate | date | recordedDate | recordedDate | |
observer | recorder (Practitioner) | provider | recorder (Practitioner) | ||
facility | recorder.extension[location] | facility | see Encounter / Location note | ||
asserter (Patient, Practitioner) | Told by OH that asserter is no longer returned | ||||
comments | note | comments | note |
MHV PHR | MHV FHIR | va.gov UI | FHIR us-core | OH FHIR | Note |
---|---|---|---|---|---|
id | id | id | id | ||
identifier(TOid) | identifier(ceuuid) | ||||
status (completed, entered-in-error) | status | status | |||
statusReason | statusReason | ||||
Immunization | vaccineCode.text | name | vaccineCode | vaccineCode.text | See CodeableConcept note |
vaccineCode.coding (cpt) | vaccineCode.coding (cvx, ndc) | ||||
patient | patient | patient | |||
encounter | see Encounter / Location note | ||||
Event Date and Time | occurrenceDateTime | date | occurrence[x] | occurrenceDateTime | |
Date Entered | recorded | ||||
primarySource (unknown) | primarySource | primarySource | |||
reportOrigin | |||||
location | location | location | |||
manufacturer | manufacture | ||||
lotNumber | |||||
expirationDate | |||||
site | |||||
route | |||||
doseQuantity | |||||
performer (provider, org) | performer | ||||
Remarks | note.text | notes | note | ||
Series | protocolApplied.series | protocolApplied (cerner codes) | may be different. See note 2 | ||
protocolApplied.doseNumberString | protocolApplied.doseNumberString | ||||
Contraindicated | |||||
protocolApplied.targetDisease | |||||
Reaction | reaction.detail.display | reactions |
Note 1: OH example
"vaccineCode": {
"coding": [
{
"system": "https://fhir.cerner.com/d45741b3-8335-463d-ab16-8c5f0bcf78ed/codeSet/72",
"code": "4145940",
"display": "tetanus, diphtheria, acellular pertussis",
"userSelected": true
},
{
"system": "http://hl7.org/fhir/sid/cvx",
"code": "115",
"display": "tetanus toxoid, reduced diphtheria toxoid, and acellular pertussis vaccine, adsorbed",
"userSelected": false
}
],
"text": "tetanus, diphtheria, acellular pertussis"
}
Note 2: OH example
"protocolApplied": [
{
"targetDisease": [
{
"coding": [
{
"system": "https://fhir.cerner.com/d45741b3-8335-463d-ab16-8c5f0bcf78ed/codeSet/4003106",
"code": "42348063",
"display": "TD/TDAP",
"userSelected": true
}
],
"text": "TD/TDAP"
}
],
"doseNumberString": "Unknown"
}
]
Note 3: OH location
MHV PHR | MHV FHIR | va.gov UI | FHIR us-core | OH FHIR | Note |
---|---|---|---|---|---|
id | id | id | id | ||
id | identifier (vista id for this note) | identifier | |||
status | status | status | status | ||
document type | type | type | type | See CodeableConcept note | |
standard title | type.text (standard title) | ||||
type (PN, DS, CR) | type.coding | type | |||
clinical-note |
category | category | category | will have clinical-note |
|
patient | subject | subject | subject | ||
timestamp | date | date / sortByDate / dateEntered | date | date | |
author/dictator | author | writtenBy | author | author | |
signed by | authenticator | signedBy | authenticator | ||
release date/time | authenticator.extension[when] | dateSigned | content.attachment.creation | updated each update and each signature | |
custodian | custodian | ||||
description | |||||
content (1..1) | content (1..*) | content (1..*) | Note Cerner often has many formats | ||
text/plain |
content.attachment.contentType (text/plain) | content.attachment.contentType | content.attachment.contentType | ||
report text | content.attachment.data | note | content.attachment.data | ||
content.attachment.url | content.attachment.url | must retrieve document stream | |||
name | content.attachment.title | name | content.attachment.title | ||
reference date/time | content.attachment.creation | content.attachment.creation | |||
content.format | content.format | ||||
context.encounter | context.encounter | context.encounter | see Encounter / Location note | ||
episode begin/end | context.period | admissionDate / dischargeDate | context.period | context.period | |
visit location | context.related (Location) | location | context.related | see Encounter / Location note | |
admittedBy={ATTENDING:} |
may have a CPT code
FHIR us-core has constrained Vitals very well, so the difference is not much. Although OH FHIR indicates it supports other elements, this is a general statement about Observation. They don't have a Vitals specific listing.
MHV PHR | MHV FHIR | va.gov UI | FHIR us-core | OH FHIR | Note |
---|---|---|---|---|---|
id | id | id | |||
extensions | 3 extensions identified, but not likely used for Vitals | ||||
type.id | identifier | identifier | |||
status | status | status | |||
category (vital-signs) | category | category (laboratory, social history, vital-signs) |
Need to search on vital-signs. | ||
type.name | code | name | code | code | See CodeableConcept note |
patient | subject (Patient) | subject | subject (Patient) | ||
encounter | see Encounter / Location note | ||||
timestamp | effectiveDateTime | date | effective[x] | effectiveDateTime | |
issued | |||||
recorder + observer | performer | performer | performer | ||
location | performer.extension[site] | location | |||
value1 / units | value[x] | measurement(valueQuantity) | value[x] | value[x] | |
dataAbsentReason | dataAbsentReason | ||||
interpretation | |||||
notes | note | ||||
referenceRange | |||||
hasMember | |||||
x | component.code | x | component.code | component.code | |
value1 / units | component.value[x] | measurement(systolic/diastolic) | component.value[x] | component.value[x] | |
component.dataAbsentReason | component.dataAbsentReason |
https://wiki.cerner.com/display/public/reference/Understand+R4+Observation+Resource+Cerner+Millennium+Mappings
Labs are handled very differently between MHV FHIR and OH FHIR. Where MHV FHIR is organized around a DiagnosticReport, OH has no DiagnosticReport. The MHV FHIR use of DiagnosticReport reflects the way the data are organized in Vista and the way they are organized as they are passed to MHV, where the only clear identifier MHV has is the DiagnosticReport identifier. MHV FHIR has Observations, but they are contained in the DiagnosticReport as that is all we can track and de-duplicate based on. This is not surprising as with Chem-Hem there is no presentedForm, so there is no overall report text.
MHV PHR | MHV FHIR | va.gov UI | FHIR us-core |
---|---|---|---|
DiagnosticReport.id | id | DiagnosticReport.id | |
id | DiagnosticReport.identifier[TOid] | ||
icn={icn} | DiagnosticReport.subject | DiagnosticReport.subject | |
stationNumber={namespaceId} | DiagnosticReport.performer[org1] | collectingLocation | DiagnosticReport.performer |
recordSubType | |||
orderedTest = {displayText} | ServiceRequest[n].code | testType | ServiceRequest[n].code |
labTestName={originalText} | Observation[m].code | results | Observation[m].code |
status | Observation[m].status | results | Observation[m].status |
result | Observation[m].value[x] | results | Observation[m].value[x] |
units | Observation[m].valueQuantity.units | results | |
resultIndicator | Observation[m].interpretation | results | |
referenceRange | Observation[m].referenceRange.text | results | |
interpretation | Observation[m].note.text | results | |
performingLocation={location} | Observation[m].performer[org2] | results | |
performingLocationName={name} | |||
orderingProvider={name} | ServiceRequest[n].requester | orderedBy | ServiceRequest[n].requester |
comments | DiagnosticReport.extension[notes] | comments | |
labType | DiagnosticReport.code.text | DiagnosticReport.code | |
collectedOnDatePrecise | Specimen.collectedDateTime *.effectiveDateTime |
date / sortDate | DiagnosticReport.effectiveDateTime |
recordId | DiagnosticReport.identifier[Rid] | ||
specimenSource={displayText} | Specimen.type | sampledTest | |
orderingLocation={name} | ServiceRequest[n].performer[org3] | ||
reportCompleteDatePrecise | DiagnosticReport.issued Observation(s).issued |
DiagnosticReport.issued | |
DiagnosticReport.category=LAB |
DiagnosticReport.category=LAB |
||
DiagnosticReport.category=v2-0074#CH |
type =CHEM_HEM |
||
DiagnosticReport.status | DiagnosticReport.status | ||
Specimen.status=available |
|||
Specimen.request = {ServiceRequest} | |||
ServiceRequest[n].category=Laboratory procedure |
ServiceRequest[n].category | ||
ServiceRequest[n].status=unknown |
ServiceRequest[n].status | ||
ServiceRequest[n].intent=order |
ServiceRequest[n].intent | ||
Observation[m].category=laboratory |
Observation[m].category=laboratory |
||
Observation[m].specimen = {Specimen} | |||
Observation[m].basedOn={ServiceRequest(s)} | |||
DiagnosticReport.basedOn={ServiceRequest(s)} | name | ||
DiagnosticReport.result={Observation(s)} | DiagnosticReport.result | ||
category=Chemistry and hematology |
|||
Observation[m].dataAbsentReason | |||
Observation[m].subject | Observation[m].subject | ||
Observation[m].effective[x] | |||
ServiceRequest[n].subject | ServiceRequest[n].subject | ||
ServiceRequest[n].occurrence[x] | |||
ServiceRequest[n].authoredOn |
MHV PHR | MHV FHIR | va.gov UI | FHIR us-core |
---|---|---|---|
DiagnosticReport.id | id | DiagnosticReport.id | |
id | DiagnosticReport.identifier[TOid] | ||
DiagnosticReport.identifier[Rid] | |||
DiagnosticReport.identifier[casenum] | |||
icn={icn} | DiagnosticReport.subject | DiagnosticReport.subject | |
DiagnosticReport.status=final |
DiagnosticReport.status | ||
DiagnosticReport.category=LAB |
DiagnosticReport.category=LAB |
||
DiagnosticReport.category.coding=http://terminology.hl7.org/CodeSystem/v2-0074#MB |
type=MICROBIOLOGY |
||
DiagnosticReport.code.coding=LOINC#18725-2 |
DiagnosticReport.code | ||
DiagnosticReport.effectiveDateTime | dateCompleted | DiagnosticReport.effectiveDateTime | |
completedDateTime[x] | DiagnosticReport.issued | DiagnosticReport.issued | |
stationNumber orderingLocation performingLocation |
DiagnosticReport.performer(Org) | labLocation | |
Observation[m].performer={DiagnosticReport.performer(Org)} | |||
DiagnosticReport.result={Observation} | DiagnosticReport.result | ||
DiagnosticReport.specimen={Specimen} | |||
reportText | DiagnosticReport.presentedForm.data | results | |
orderedTest | |||
orderingProvider | DiagnosticReport.performer(Pra) | orderedBy | DiagnosticReport.performer |
specimenSource | Specimen.collection.bodySite | sampleTested | |
collectionSample | Specimen.type.text | ||
collectedDateTime[x] | Specimen.collectedDateTime | ||
DiagnosticReport.issued | |||
DiagnosticReport.code.text | name / labType | ||
Specimen.status=available |
|||
Specimen.type.text | sampleFrom | ||
Specimen.collectedDateTime | date / sortDate | ||
Specimen.accessionIdentifier | |||
Specimen.identifier | |||
Observation[m].issued | |||
Observation[m].valueString | Observation[m].value[x] | ||
Observation[m].identifier[TOid] | Observation[m].code | ||
Observation[m].code.text | |||
Observation[m].code.coding | |||
Observation[m].specimen={Specimen} | |||
Observation[m].status=final |
Observation[m].status | ||
Observation[m].category=laboratory |
Observation[m].category=laboratory |
||
Observation[m].issued={DiagnosticReport.issued} | |||
Observation[m].effectiveDate={DiagnosticReport.effectiveDate} | Observation[m].effective[x] | ||
name=Microbiology |
|||
Observation[m].dataAbsentReason | |||
ServiceRequest[n].status | |||
ServiceRequest[n].intent | |||
ServiceRequest[n].category | |||
ServiceRequest[n].code | |||
ServiceRequest[n].subject | |||
ServiceRequest[n].occurrence[x] | |||
ServiceRequest[n].authoredOn | |||
ServiceRequest[n].requester |
Note it is uncommon for Observations on Pathology.
MHV PHR | MHV FHIR | va.gov UI | FHIR us-core |
---|---|---|---|
DiagnosticReport.id | id | DiagnosticReport.id | |
id | DiagnosticReport.identifier[TOid] | ||
DiagnosticReport.identifier[Rid] | |||
icn={icn} | DiagnosticReport.subject | DiagnosticReport.subject | |
DiagnosticReport.status=final |
DiagnosticReport.status | ||
DiagnosticReport.category.coding[us-core]=LOINC#LP7839-6 |
pathology |
DiagnosticReport.category[us-core] | |
DiagnosticReport.category.coding[SPLabSlice]=v2-0074#SP |
|||
typeOfReport | DiagnosticReport.code.coding` | code | DiagnosticReport.code |
DiagnosticReport.code.text | name | ||
reportText | DiagnosticReport.presentedForm.data | labComments | |
specimen | Specimen.type.text | ||
collectedDateTime[x] | Specimen.collectedDateTime DiagnosticReport.effectiveDateTime |
date / dateCollected / sortDate | DiagnosticReport.effective[x] |
completedDateTime[x] | DiagnosticReport.issued | DiagnosticReport.issued | |
DiagnosticReport.performer(Pra) | orderedBy | DiagnosticReport.performer | |
performingLocation | DiagnosticReport.performer(Org) | collectingLocation | DiagnosticReport.performer |
stationNumber={namespaceId} | Observation[m].performer={DiagnosticReport.performer(Org)} | ||
DiagnosticReport.result={Observation} | DiagnosticReport.result | ||
DiagnosticReport.specimen={Specimen} | |||
Specimen.status=available |
|||
Specimen.type.text | sampleTested | ||
Specimen.accessionIdentifier | |||
Specimen.identifier | |||
Observation[m].issued | |||
DiagnosticReport.performer(Org) | |||
DiagnosticReport.identifier[casenum] | |||
Observation[m].valueString | Observation[m].value[x] | ||
Observation[m].identifier[TOid] | |||
Observation[m].code.text | Observation[m].code | ||
Observation[m].code.coding | |||
Observation[m].specimen={Specimen} | |||
Observation[m].status=final |
Observation[m].status | ||
Observation[m].category=laboratory |
Observation[m].category=laboratory |
||
Observation[m].issued={DiagnosticReport.issued} | |||
Observation[m].effectiveDate={DiagnosticReport.effectiveDate} | Observation[m].effective[x] | ||
labLocation=NULL | |||
Observation[m].dataAbsentReason | |||
ServiceRequest[n].status | |||
ServiceRequest[n].intent | |||
ServiceRequest[n].category | |||
ServiceRequest[n].code | |||
ServiceRequest[n].subject | |||
ServiceRequest[n].occurrence[x] | |||
ServiceRequest[n].authoredOn | |||
ServiceRequest[n].requester |
Oracle-Health focuses on the Observation resource, these would be grouped Observation.basedOn
by a ServiceRequest (order). There might be a DiagnosticReport if there is a presented form. We might need to navigate to the Encounter to get some physical location specifics. ServiceRequest.category
will have a defined code for laboratory
, but OH does not support search by .category
; thus one must search by .code
.
ServiceRequest
for this Patient
. This gives ALL of the ServiceRequests available, which may include many things beyond LabsSearch within the Bundle results for category = {codeSystem-6000} |
2513 "Laboratory" |
ServiceRequest
of interestObservation.basedOn
of a ServiceRequest
of interestDiagnosticReport.basedOn
of a ServiceRequest
of interestDocumentReference.basedOn
of a ServiceRequest
of interestServiceRequest.encounter
if doing searches only for updated information, then search for Observation with a category of laboratory
that have changed (lastUpdated) since the last time. From this, look if there is an updated DocumentReference or DiagnosticReport.
If MHV is going to proxy copy the FHIR data from OH; then we could use the ServiceRequest.category to make the above much more efficient. We can make ServiceRequest.category searchable, and support _revInclude on the Observations, DiagnosticReport, and DocumentReference.
Hold time:
Notes:
DiagnosticReport.conclusionCode
, if populated, would be the normalcy code (codeset 52) on the clinical event table (e.g. normal, abnormal, high, critical, etc)OH documentation CernerWiki
MHV PHR_RADIOLOGY | MHV FHIR | va.gov UI | FHIR us-core | OH FHIR | Note |
---|---|---|---|---|---|
DiagnosticReport.category = LOINC#LP29684-5 Radiology | #LP29684-5 | #LP29684-5 | |||
DiagnosticReport.subject = {patient} | subject | subject | |||
DiagnosticReport.status = final | entered-in-error |
status | status | |||
DiagnosticReport.code | code | code | See CodeableConcept note | ||
DiagnosticReport.basedOn = ServiceRequest | basedOn | ||||
DiagnosticReport.identifier | identifier | different kinds of identifiers | |||
DiagnosticReport.encounter | encounter | encounter | MHV FHIR is just the identifier, OH relies on Encounter | ||
eventTime | DiagnosticReport.effectiveDateTime | date | effectiveDateTime | effectiveDateTime | Period is supported by OH |
DiagnosticReport.issued | issued | issued | |||
DiagnosticReport.performer [Org] | performer | performer [Org, Pra] | MHV FHIR has organization, OH has Practitioner | ||
result | result | Unclear if there are ever Observations with a Radiology Report | |||
media.link | |||||
radiologist | DiagnosticReport.resultsInterpreter ServiceRequest.performer |
imagingProvider | resultsInterpreter [Org, Pra] | ||
DiagnosticReport.presentedForm.creation | .creation | .creation | |||
procedureName | DiagnosticReport.presentedForm.title | name | .title | .title | |
DiagnosticReport.presentedForm | presentedForm | presentedForm | |||
reporttext | (subset of presentedForm text) | ||||
impressiontext | (subset of presentedForm text) | results | |||
clinical_history | (subset of presentedForm text) | clinicalHistory | |||
reason_for_study | (subset of presentedForm text) | reason | |||
DiagnosticReport.conclusion | |||||
conclusionCode | |||||
ServiceRequest.code.text | |||||
facility | ServiceRequest.performer | ||||
requesting_provider | ServiceRequest.requester | orderedBy | |||
performing_location_st_num | imagingLocation | ||||
comments | never set | ||||
examDate | |||||
status | |||||
inpatient_outpatient | never set |
Note: MHV FHIR will always be presentedForm using .data
and text, OH often has multiple presentedForm (pdf, xml), using .url
to Binary
Questions:
The FHIR team reviewed the original information to filter based on code value on code set 200 for CATELOG_CD and have determined that those are for all the ordables in the domain.
ServiceRequest.Category which is part of code set 6000 and puts the order in a category.
Today MHV/FHIR map these to DocumentReference, but also does not get these reports anymore. OH uses DiagnosticReport.
DiagnosticReport.category = LOINC#LP29708-2 "Cardiology"
DICOM will continue to be with CVIX.