DEV Community

vitagroup HIP for vitagroup HIP

Posted on • Edited on

Part 4: Searching for data

Series by Stefan Spiska, Senior Backend Developer, PEN, vitagroup HIP

Part 4 of the series "Vendor neutral interoperability with openEHR and HL7 FHIR"

In the previous sections, it was explored how to create patients and store data in HIP. One of the most significant advantages of an open data platform with standardized formats is the ability to search for data flexibly - not just by ID but using various clinical or administrative criteria.

Example use case: Searching for systolic blood pressure in a specific Encounter

Let’s assume one wants to find all systolic blood pressure measurements in a specific Encounter, where the value is ≥ 100 mmHg.

FHIR Approach

In FHIR, one would search for Observation components with:

  • code = 8480-6 (Systolic Blood Pressure)
  • valueQuantity.value ≥ 100
  • encounter = Encounter/74aa52fc-6aff-46aa-9848-e37b013354

So the FHIR search request would be :

Observation/?component-code-value-quantity=8480-6$ge100&encounter=74aa52fc-6aff-46aa-9848-e37b013354
Enter fullscreen mode Exit fullscreen mode

Translating FHIR Search to openEHR Query

Since the FHIR Observation components was mapped to the openEHR archetype openEHR-EHR-OBSERVATION.blood_pressure.v2, the FHIR search has to be translated into an openEHR query.

Thankfully, EHRbase, as an openEHR server, provides a powerful standardised query language called AQL (Archetype Query Language).

Think of AQL as a combination of XPath and SQL, allowing us to query structured clinical data based on openEHR's Reference Model (RM).

Basic AQL Queries

Selecting Compositions:

SELECT c FROM COMPOSITION c
Enter fullscreen mode Exit fullscreen mode

would retrieve all Compositions.

Selecting Observations:

 SELECT o FROM OBSERVATION o
Enter fullscreen mode Exit fullscreen mode

This retrieves all Observations wich in openEHR are part of a Composition.

Selecting specific data fields:

SELECT c/uid/value,c/context/start_time/value COMPOSITION c
Enter fullscreen mode Exit fullscreen mode

As we can see from the RM-model definition EHR Information Model

  • c/uid/value: Navigate to uid field which is of type UID_BASED_ID and thus we can navigate the value field which contains a String containing the uid of this composition
  • c/context/start_time/value: Is the display of start time of the composition

For archetypes objects like openEHR-EHR-OBSERVATION.blood_pressure.v1 one has to look up the archetypes to get the parts.

SELECT 
o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude,
o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/units
FROM OBSERVATION o[openEHR-EHR-OBSERVATION.blood_pressure.v1]
Enter fullscreen mode Exit fullscreen mode

Previously it was shown that /data[at0001]/events[at0006]/data[at0003]/items[at0004] in the archetype openEHR-EHR-OBSERVATION.blood_pressure.v2 points to the element containing the DV_QUANTITY with the systolic blood pressure and thus we add the relative parts.

  • value/magnitude
  • value/units

To get the magnitude and unit.

Note that

o[openEHR-EHR-OBSERVATION.blood_pressure.v1]
Enter fullscreen mode Exit fullscreen mode

is just a shorthand for

o[archetype_node_id ='openEHR-EHR-OBSERVATION.blood_pressure.v1']
Enter fullscreen mode Exit fullscreen mode

which ensures that only Blood Pressure observations are queried.

Joining data across multiple structures

We can also “join“ objects which are contained in each other using the the CONTAINS clause:

SELECT
   c/uid/value,
   c/context/start_time/value,
   o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude
FROM EHR e 
  CONTAINS COMPOSITION c 
    contains OBSERVATION o[openEHR-EHR-OBSERVATION.blood_pressure.v1]
Enter fullscreen mode Exit fullscreen mode

CONTAINS defines hierarchical relationships within an EHR, similar to a structured join in SQL. In this query, it ensures that Compositions are selected from the EHR, and only Observations within those Compositions are retrieved. This allows querying structured clinical data while maintaining the context of where it is stored.

So each row

{
  "rows": [
    [
      "635775de-84fb-4ce4-bf65-71249f28953a::cdr-core-sanity-check.hip-cdr-core-ehrbase-enterprise-cdr-core-dev1.dev3.vg-hip.dev::1",
      "2022-02-03T04:05:06",
      120.0
    ],
    [
      "7d99ae32-64e3-40a7-a11f-5c5fb1aafbc0::cdr-core-sanity-check.hip-cdr-core-ehrbase-enterprise-cdr-core-dev1.dev3.vg-hip.dev::1",
      "2022-03-03T00:00:00",
      123.0
    ]
  ]
}       
Enter fullscreen mode Exit fullscreen mode

will represent a systolic blood pressure measurement together with the ehr id (patient identifier ) and start time.

Searching by Encounter

In the last part ist was shown how encounters are represented as Folders in the HIP, containing Compositions. Thus encounter = encounter/74aa52fc-6aff-46aa-9848-e37b013354 can be represented as

SELECT c 
FROM FOLDER f [openEHR-EHR-FOLDER.episode_of_care.v1]
      contains COMPOSITION c 
WHERE 
  f/uid/value = '74aa52fc-6aff-46aa-9848-e37b013354'
Enter fullscreen mode Exit fullscreen mode

Putting everything together

Since component-code was mapped to data[at0001]/events[at0006]/data[at0003]/items[at0004] in the Archetype openEHR-EHR-OBSERVATION.blood_pressure.v2 and the Composition was stored in an Encounter with Id = 74aa52fc-6aff-46aa-9848-e37b013354 the FHIR search

Observation/?component-code-value-quantity=8480-6$ge100&encounter=74aa52fc-6aff-46aa-9848-e37b013354
Enter fullscreen mode Exit fullscreen mode

can be represented as the following AQL query:

SELECT DISTINCT c 
FROM FOLDER f [openEHR-EHR-FOLDER.episode_of_care.v1]
      contains COMPOSITION c 
              contains OBSERVATION o[openEHR-EHR-OBSERVATION.blood_pressure.v2]
WHERE 
  f/uid/value = '74aa52fc-6aff-46aa-9848-e37b013354'
AND
  o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/magnitude >= 100                
Enter fullscreen mode Exit fullscreen mode

The HIP-Bridge will read the mappings to automatically transform FHIR search Request to AQL, and transforming the resulting data back to FHIR.

Thus through the capabilities of the HIP Bridge, users can query data in two ways: using FHIR Search or the Archetype Query Language. This ensures to meet the needs to system integrations and application developers alike with different views and access mechanisms on the data.

Conclusion

In this blog series, we have explored how HIP (Health Intelligence Platform) enables vendor neutral interoperability by integrating legacy healthcare data into openEHR and HL7 FHIR. We have seen how data can be transformed into FHIR and openEHR formats, ensuring structured, standardised, and semantically rich data storage.

By leveraging PSPL (Protocol Specific Path Language) and AQL (Archetype Query Language), we demonstrated how data can be mapped, stored, and efficiently queried, allowing healthcare providers to move beyond simple ID-based searches and perform complex, criteria-driven queries. This level of data accessibility and interoperability empowers organizations to build advanced health applications, enhance clinical decision making, and improve patient outcomes.

With a vendor neutral and standards based approach, HIP provides a future proof foundation for seamless data exchange between healthcare systems. As healthcare continues to evolve, adopting open data models and interoperability frameworks like openEHR and FHIR will be essential for achieving truly connected and patient centric healthcare ecosystems.

About the Author – Stefan Spiska

Stefan Spiska is a Senior Software Developer at vitagroup, specializing in interoperability and open platform development in the E-Health sector. With extensive experience in healthcare IT, he is a core developer for the open source openEHR platform, EHRbase (ehrbase.org).

AWS Q Developer image

Your AI Code Assistant

Ask anything about your entire project, code and get answers and even architecture diagrams. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Start free in your IDE

Top comments (0)

Playwright CLI Flags Tutorial

5 Playwright CLI Flags That Will Transform Your Testing Workflow

  • 0:56 --last-failed
  • 2:34 --only-changed
  • 4:27 --repeat-each
  • 5:15 --forbid-only
  • 5:51 --ui --headed --workers 1

Learn how these powerful command-line options can save you time, strengthen your test suite, and streamline your Playwright testing experience. Click on any timestamp above to jump directly to that section in the tutorial!

Watch Full Video 📹️