How to use Persistent Compositions?

My openEHR experience is still on a high level, so please excuse if this is a trivial question!

We were looking at how to set up a strategy for persistent archetypes versus a folder structure for keeping various types of aggregated lists. We also discussed why we cannot just query for what is in the lists, without the persistent compositions.

What is the reason for having a persistent composition as opposed to just query for a list of something?

Should persistent compositions be used only when there is a curated list, ie a user actively manages the content on the list, adding only a subset of the type of information that is in the list? Of course, that means that list needs to be explicitly saved and cannot be queried without the persistent composition.

If we look at a Problem list as an example, is the intention that only some problems should be on the list?

It feels like it is intended to be used as a simple to access updated list of something? If so, does that mean we should create new persistent composition archetypes for things like “Appointment list” if we want to easily access the list of a patient’s planned appointments? Of course, there can be any such number of “lists” which all would require a persistent composition.

An option is then of course to just query for the list without using persistent compositions.

Can someone help explain a bit more how to use persistent compositions, and what is a good strategy for having them, and when it is good to just query for data that is needed (or use the Folders in some way).

Thanks!

1 Like

Hi Martin,

Excuse the quick response

Persistent compositions fall into 2 categories -

curated lists (problems, allergies)

and single sources of truth

e.g an End of life care document, housing status, current employment.

It is difficult to be precise because this is actually more about the scope of the ‘system’ and the clinical governance processes than the technology. So in a national data platform like Scotland , we expect to have a large number of persistent compositions, where in a hospital ‘‘epidoic-care’ system these might just be captured in ‘events’ as there is n real mechanism to curate and maintain this data over time, other than perhaps for that episode of care - which is why we are introducing ‘episodic’’.

It really is about you Create/Update (POST/PUT) strategy for a particular piece of information.

3 Likes

Something I wrote before that might help

Working with ‘persistent’ compositions in openEHR Ehrscape

Most openEHR data instance compositions will use event style persistence, where a new copy of the composition is normally created each time that data is persisted, and compositions are only updated if an error correction or adjustment is required.

In contrast, a less common requirement in openEHR systems is to be able to maintain a single instance of a composition instance and to continually update that single instance. In openEHR terms this is a persistent composition.

Common use-cases might be…

  • Documents for which a single critical source of truth is important e.g. Cardiac resuscitation wishes.
  • Documents which are maintained as curated summaries - e.g. problem lists, allergy lists, immunisation lists
  • Documents which track simple workflows e.g. consent to share information status.

The API and data examples provided below make use of the Better (Marand) Ehrscape API and associated JSON formats but the principles can be applied to the formal openEHR REST API and JSON/XML formats.
openEHR / Ehrscape API approach

General approach

  1. Run an AQL query to look for a previous instance of the composition (there should only ever by one in a production environment).

  2. If no such instance exists, construct the data and then perform a POST /composition call to persist the data as a new composition instance.

  3. If there is a previous instance, run the GET /composition call against the composition Uid to retrieve the most recent version, edit the data, then persist the updated data using the PUT / composition call (or DELETE if the composition is to be logically deleted).

Posting the initial composition instance version

This makes use of the normal openEHR/Ehrscape POST /composition call but an understanding of the difference between Marand FLAT/STRUCTURED INPUT and OUTPUT formats is helpful, as the FLAT/STRUCTURED OUTPUT format matches the format returned by GET /composition and is therefore more easily updated by a subsequent PUT.

Marand introduced 2 forms of flattened JSON formats to make openEHR compositions easier to work with, by flattening some complex paths and hiding boilerplate datapoints. Both STRUCTURED and FLAT formats have INPUT and OUTPUT variants. Significantly, the OUTPUT variant matches that returned by the GET /composition call. If you are expecting a sequence of a POST, followed by repeated cycles of GET and PUT /composition, it may make more sense to work purely with the OUTPUT format.

The INPUT format is helpful for simpler use-cases as it uses the ctx block to sensibly apply defaults to a number of mandatory elements throughout the composition, in particular language and territory descriptors, and mandatory dates such as the ACTION.time attribute i.e this will default to the composition.context.start_time attribute, though in all cases these can be overriden.

The examples below are all based in a simple composition used to track consent to share information. Patient’s can provide or refuse consent - these are recorded by changing the ism_transition settings in the ACTION.informed_consent archetype, with only the current consent status being normally visible.

FLAT INPUT JSON example

{
    "ctx/language": "en",
    "ctx/territory": "GB",
    "ctx/composer_name": "Silvia Blake",
    "ctx/id_namespace": "Apperta",
    "ctx/id_scheme": "Apperta",
    "ctx/time": "2019-03-05T13:19:56.211Z",

    "ctx/health_care_facility|name": "Home",
    "ctx/health_care_facility|id": "0000",
    "physical_health_app_admin/consent/ism_transition/current_state|code": "245",
    "physical_health_app_admin/consent/ism_transition/current_state|value": "active",
    "physical_health_app_admin/consent/ism_transition/careflow_step|code": "at0015",
    "physical_health_app_admin/consent/ism_transition/current_state|value": "Informed Consent Provided",  
    "physical_health_app_admin/consent/procedure_trial_activity:0": "Consent to Physical Health data sharing",
    "physical_health_app_admin/consent/consent_description": "Delighted to be consenting",
}

Note that in this example there is no date associated specifically with the consent itself, only the ctx/time (which is the time that the document was authored).

if we now perform a GET /composition and retrieve this stored data, you will see the following

FLAT OUTPUT JSON

{
  "ctx/language": "en",
  "ctx/territory": "GB",
  "physical_health_app_admin/_uid": "0bd5ea9d-231f-4bb3-bb06-6db4844b1c54::92aac94f-47f7-46fd-8e25-2c41da92698e::2",
        "physical_health_app_admin/language|code": "en",
        "physical_health_app_admin/language|terminology": "ISO_639-1",
        "physical_health_app_admin/territory|code": "GB",
        "physical_health_app_admin/territory|terminology": "ISO_3166-1",
        "physical_health_app_admin/context/_health_care_facility|id": "0000",
        "physical_health_app_admin/context/_health_care_facility|id_scheme": "Apperta",
        "physical_health_app_admin/context/_health_care_facility|id_namespace": "Apperta",
        "physical_health_app_admin/context/_health_care_facility|name": "Home",
        "physical_health_app_admin/context/start_time": "2019-03-22T17:49:50.511Z",
        "physical_health_app_admin/context/setting|code": "238",
        "physical_health_app_admin/context/setting|value": "other care",
        "physical_health_app_admin/context/setting|terminology": "openehr",
        "physical_health_app_admin/consent/ism_transition/current_state|code": "245",
        "physical_health_app_admin/consent/ism_transition/current_state|value": "active",
        "physical_health_app_admin/consent/ism_transition/current_state|terminology": "openehr",
        "physical_health_app_admin/consent/ism_transition/careflow_step|code": "at0015",
        "physical_health_app_admin/consent/ism_transition/careflow_step|value": "Informed Consent Provided",
        "physical_health_app_admin/consent/ism_transition/careflow_step|terminology": "local",
        "physical_health_app_admin/consent/procedure_trial_activity:0": "Consent to Physical Health data sharing",
        "physical_health_app_admin/consent/consent_description": "Delighted to be consenting",
        "physical_health_app_admin/consent/time": "2019-03-05T13:20:19.857Z",
        "physical_health_app_admin/consent/language|code": "en",
        "physical_health_app_admin/consent/language|terminology": "ISO_639-1",
        "physical_health_app_admin/consent/encoding|code": "UTF-8",
        "physical_health_app_admin/consent/encoding|terminology": "IANA_character-sets",
        "physical_health_app_admin/category|code": "433",
        "physical_health_app_admin/category|value": "event",
        "physical_health_app_admin/category|terminology": "openehr",
        "physical_health_app_admin/composer|name": "Silvia Blake"
    },

You will observe that a whole new set of data points has appeared. Let’s work through these individually.

A. The uid that is assigned to the composition when it is first created or is updated. This will be ignored if the composition is re-commited via a PUT, in which case the version number at the end of the string is incremented.

        "physical_health_app_admin/_uid": "0bd5ea9d-231f-4bb3-bb06-6db4844b1c54::92aac94f-47f7-46fd-8e25-2c41da92698e::1"}

B. the language and territory information derived from the original ctx/language and ctx/territory attributes in the submitted composition. This can be supplied as Boilerplate in the UK. Note that there is a bug in earlier version of the Ehrscape library, including that used by Ethercis which requires the ctx/language and ctx/territory attributes to be provided even though this should not be necessary if the exapnded forms are provided.

```JSON
        "physical_health_app_admin/language|code": "en",
        "physical_health_app_admin/language|terminology": "ISO_639-1",
        "physical_health_app_admin/territory|code": "GB",
        "physical_health_app_admin/territory|terminology": "ISO_3166-1",

        "ctx/language": "en",
        "ctx/territory": "GB",
      |  
```  |  

C.  The healthcare facility information derived from the original `ctx/health_care_facility' attribute in the submitted composition. For a given template, this can almost certainly be boilerplated unless the place where it is being commited may differ.
|  
```JSON
    "physical_health_app_admin/context/_health_care_facility|id_scheme": "apperta"
    "physical_health_app_admin/context/_health_care_facility|id_namespace": "apperta",
    "physical_health_app_admin/context/_health_care_facility|name": "Home",

D. The start_time of the composition, derived from ctx/time in the submitted composition. This will normally be the date of the original commit, or anty more recent update. It is intended to hold the ‘clinically authored date’, which might in some circumstances be different from the commit date e.g if a document is committed by a member of admin staff some time after the original authoring. Normally though, commit date is sufficiently close.

    "physical_health_app_admin/context/start_time": "2019-03-22T17:49:50.511Z",

E. The ‘other care’ setting is added as a default value, which will suffice in many cases.

    "physical_health_app_admin/context/setting|code": "238",
    "physical_health_app_admin/context/setting|value": "other care",
    "physical_health_app_admin/context/setting|terminology": "openehr",

E. The ‘category’ setting is added as a default value of ‘event’, which will suffice in most cases.

 "physical_health_app_admin/category|code": "433",
 "physical_health_app_admin/category|value": "event",
 "physical_health_app_admin/category|terminology": "openehr",

E. The ‘composer’ setting is derived from ctx/composer.

  "physical_health_app_admin/composer|name": "Silvia Blake",

F. These data items will be derived from the UI/data entry

a) Where the patient has consented…

"physical_health_app_admin/consent/ism_transition/current_state|code": "245",  
"physical_health_app_admin/consent/ism_transition/current_state|value": "active",
"physical_health_app_admin/consent/ism_transition/current_state|terminology": "openehr",
"physical_health_app_admin/consent/ism_transition/careflow_step|code": "at0015",
"physical_health_app_admin/consent/ism_transition/careflow_step|value": "Informed Consent Provided",
"physical_health_app_admin/consent/ism_transition/careflow_step|terminology": "local",
  "physical_health_app_admin/consent/procedure_trial_activity:0": "Consent to Physical Health data sharing",
  "physical_health_app_admin/consent/consent_description": "Delighted to be refusing",

b) Where the patient has refused consent…

"physical_health_app_admin/consent/ism_transition/current_state|code": "531",  
"physical_health_app_admin/consent/ism_transition/current_state|value": "aborted",
"physical_health_app_admin/consent/ism_transition/current_state|terminology": "openehr",
"physical_health_app_admin/consent/ism_transition/careflow_step|code": "at0016",
"physical_health_app_admin/consent/ism_transition/careflow_step|value": "Informed Consent Refused",
"physical_health_app_admin/consent/ism_transition/careflow_step|terminology": "local",
  "physical_health_app_admin/consent/procedure_trial_activity:0": "Consent to Physical Health data sharing",
  "physical_health_app_admin/consent/consent_description": "Delighted to be refusing consent",

G. The time that the consent decision ACTION was actually made. This normally equates to the start_time of the composition and is derived automatically from ctx/time unless overriden, as here.

  "physical_health_app_admin/consent/time": "2019-03-05T13:20:19.857Z",

H. The language of the Consent ACTION - boilerplate in the UK.

  "physical_health_app_admin/consent/language|code": "en",
  "physical_health_app_admin/consent/language|terminology": "ISO_639-1",

I. H. The encoding of text inside the Consent ACTION - boilerplate in the UK.

  "physical_health_app_admin/consent/encoding|code": "UTF-8",
  "physical_health_app_admin/consent/encoding|terminology": "IANA_character-sets",

This format is clearly more complex but has the advantage of being directly committable back via PUT /composition using FLAT OUTPUT format

STRUCTURED formats

Identical principles apply to the STRUCTURED OUTPUT JSON format. Note that this is not currently supported by the library used by Ethercis.

{
  "ctx/language": "en",
  "ctx/territory": "GB",
  "physical_health_app_admin": {
    "language": [
      {
        "|code": "en",
        "|terminology": "ISO_639-1"
      }
    ],
    "territory": [
      {
        "|code": "GB",
        "|terminology": "ISO_3166-1"
      }
    ],
    "context": [
      {
        "_health_care_facility": [
          {
            "|id": "0000",
            "|id_scheme": "HOSPITAL-NS",
            "|id_namespace": "HOSPITAL-NS",
            "|name": "Home"
          }
        ],
        "start_time": [
          "2019-03-22T17:49:50.511Z"
        ],
        "setting": [
          {
            "|code": "238",
            "|value": "other care",
            "|terminology": "openehr"
          }
        ]
      }
    ],
    "consent": [
      {
        "ism_transition": [
          {
            "current_state": [
              {
                "|code": "245",
                "|value": "active",
                "|terminology": "openehr"
              }
            ]
          },
          {
            "careflow_step": [
              {
                "|code": "at0015",
                "|value": "Informed Consent Provided",
                "|terminology": "local"
              }
            ]
          }
        ],
        "procedure_trial_activity": [
          "Consent to Physical Health data sharing"
        ],
        "consent_description": [
          "Delighted to be consenting"
        ],
        "time": [
          "2019-03-05T13:20:19.857Z"
        ],
        "language": [
          {
            "|code": "en",
            "|terminology": "ISO_639-1"
          }
        ],
        "encoding": [
          {
            "|code": "UTF-8",
            "|terminology": "IANA_character-sets"
          }
        ]
      }
    ],
    "category": [
      {
        "|code": "433",
        "|value": "event",
        "|terminology": "openehr"
      }
    ],
    "composer": [
      {
        "|name": "Silvia Blake"
      }
    ]
  }
}

4 Likes

Thanks Ian!
I think curated list makes a lot of sense, seems like a straight forward starting strategy.

The things that there can be only one of is a bit more complex. There is often a history of End of life care documents, housing statements and current employment, and at least within an EHR you need to know exactly what was valid at any given time. Ie, we in the EHR world would normally do a POST/create new for each new “event”, and query for the latest one to display or use in business logic.

But I get in a national platform being fed from the various EHRs on the national market you may only be interested in the “latest” data, the rest is up to each EHR to manage.

So I think I get what you mean :slight_smile:

1 Like

Yes - it is all about how much control you can exert!!In a national system or large region, I would want there to be a single ‘patient’ record that for many of those patient-centric facts and for there only ever to be the current version. But that is often not possible .

1 Like