Stream: cql
Topic: resolving references
Georg Fette (Jan 29 2020 at 10:09):
Hi, when I would like to access fields of a referenced resource, e.g.:
[Observation] a where a.encounter.status = something
How do I express that in CQL ?
The above statement raises the error "Member status not found for type FHIR.Reference."
Alexander Kiel (Jan 29 2020 at 15:26):
You can't traverse references this way in CQL. A FHIR reference in CQL is just that, the reference data type with its fields. I also assumed and even implemented reference traversal in my engine at the beginning. What you can do, is to use relationships in query:
[Observation] a with [Encounter] b such that b.status = something and EndsWith(a.encounter. reference, b.id)
I don't like the approach to use EndsWith
on Reference.reference
but that's the only thing I came up with. In all examples, I known of, they don't need such things like joining by id. Maybe we miss something here.
Bryn Rhodes (Jan 29 2020 at 15:34):
We are pursuing several different approaches right now, the first is to join like @Alexander Kiel suggested, though we often use functions to support that (an example here). Second is using a related context retrieve, though the FHIR model included with the current translator doesn't have enough information to work that out yet, and the Third is to enable the natural traversal in the original question (a.encounter.status = something
), but that requires some additional tooling that is still in development in both the translator and the engine.
Alexander Kiel (Jan 29 2020 at 15:39):
@Bryn Rhodes Is there a specification for the natural traversal? I thought one important point in CQL was, that one is able to calculate the data needed for a query and that the Retrieve expression was specially designed for that reason. With such a natural traversal, additional data might be required which is not visible through Retrieve.
Bryn Rhodes (Jan 29 2020 at 16:14):
Well, the working idea of the natural traversal is that it would be an aspect of representation in the CQL, but the underlying ELM would still be expressed in terms of the actual retrieves.
Georg Fette (Feb 11 2020 at 08:46):
I would highly apprecitate such natural traversals. I would as well accept a workaround like in FHIRPath with a "resolve()" call. The solution with a join would be highly inefficient when it is needed to make a full iteration over another profile just to find the one that is referenced. The solution with the function obfuscating this full iteration would make the code more readable but still stays inefficient. As FHIR is a very graph like system it is necessary to be able to traverse all relations as transparent as possible to make it easily usable by everyone.
Bryn Rhodes (Feb 11 2020 at 14:57):
Hi @Georg Fette , this is on the short list for items to be addressed in the upcoming CQL ballot.
Chris Moesel (Mar 24 2021 at 19:50):
Someone (@Saul Kravitz) recently asked me about traversing references... do we have any good examples of this now? I know CQL 1.5 introduces resolve
, but we're looking for the old school approach w/ sub-queries since that currently has better support. The example @Bryn Rhodes linked to above is broken, but I reckon there must be other examples out there. If not, I can craft one, but I'm hoping for a battle-tested solution. ;-)
Bryn Rhodes (Mar 24 2021 at 21:07):
Here's an updated link to that example:
Bryn Rhodes (Mar 24 2021 at 21:07):
Bryn Rhodes (Mar 24 2021 at 21:07):
And an example of usage just a few lines below that:
Bryn Rhodes (Mar 24 2021 at 21:07):
Bryn Rhodes (Mar 24 2021 at 21:08):
It's a limited use solution in that it assumes single-server evaluation and referencing.
Bryn Rhodes (Mar 24 2021 at 21:08):
But it is functional and we have used that approach in both quality measure and decision support logic.
Bryn Rhodes (Mar 24 2021 at 21:10):
And here's another example, slightly more complex "plural" reference, in answer to this same question from @Aziz Boxwala :
library EncountersForDiabetesExample
using FHIR version '4.0.1'
include FHIRHelpers version '4.0.1'
valueset Diabetes: 'TBD'
context Patient
define EncountersForDiabetes:
[Encounter] E
with [Condition: "Diabetes"] C such that C.id in E.reasonReference R return Last(Split(R.reference, '/'))
Chris Moesel (Mar 24 2021 at 21:16):
Thanks, @Bryn Rhodes. Since you passed that challenge w/ flying colors... I don't suppose you have any examples where the reference is a choice, do you? E.g., Condition.stage.assessment
is a Reference(ClinicalImpression|DiagnosticReport|Observation)
. It's a little more tricky when you effectively have to issue different queries depending on the reference. If you don't have an example, don't worry about it -- it's not rocket science and I can figure something out; but it's always nice to look for existing stuff first.
Bryn Rhodes (Mar 24 2021 at 21:23):
I can't think of an example of that specifically, but I have a similar one, where the reference is choice of CodeableConcept or Reference:
define "Active Ambulatory Naloxone Rx":
(
("Get Active Ambulatory Medication Requests"([MedicationRequest])) MR
where date from MR.authoredOn 2 years or less on or before Today()
and MR.medication is Reference or MR.medication in "Naloxone medications"
) Rx
let Med: if Rx.medication is Reference then singleton from ([Medication: id in (Last(Split((Rx.medication as FHIR.Reference).reference, '/')))]) else null
where not(Rx.medication is Reference) or Med.code in "Naloxone medications"
return
MedicationRequest {
id: Rx.id,
status: Rx.status,
intent: Rx.intent,
category: Rx.category,
medication: if Rx.medication is Reference then Med.code else Rx.medication as CodeableConcept,
subject: Rx.subject,
recorder: Rx.recorder,
dosageInstruction: Rx.dosageInstruction,
dispenseRequest: Rx.dispenseRequest
}
Aziz Boxwala (Mar 24 2021 at 21:24):
Thank you @Bryn Rhodes .
Bryn Rhodes (Mar 24 2021 at 21:25):
That medication example is functional against servers that use MedicationRequest with a reference to a Medication, as well as servers that use MedicationRequest with a CodeableConcept.
Bryn Rhodes (Mar 24 2021 at 21:25):
And we're currently working on some planning code that will turn the related retrieve into an include so that it only hits the server once.
Bryn Rhodes (Mar 24 2021 at 21:27):
@Aziz Boxwala , on that example of "Encouters for Diabetes", do you also want to consider Encounters that have a "diagnosis" element referencing a diabetes condition?
Aziz Boxwala (Mar 24 2021 at 21:29):
@Bryn Rhodes Should there be something in FHIRHelpers to handle references better so we hide away this ugly code: Last(Split(R.reference, '/'))
or even C.id in E.reasonReference R return Last(Split(R.reference, '/'))
Bryn Rhodes (Mar 24 2021 at 21:41):
Yes, and the latest translator release (1.5.2) does support the following:
// If a reference is resolved in the scope of a query, that resolve can be rewritten as an include in the retrieve for that source
// MedicationRequest
define TestMedicationRequest1:
[MedicationRequest] MR
where MR.medication.reference.resolve().as(Medication).code ~ "aspirin 325 MG / oxycodone hydrochloride 4.84 MG Oral Tablet"
// Expected FHIR URL for the retrieve
// [base]/MedicationRequest?patient=123&_include=MedicationRequest:medication
define TestMedicationRequest1A:
[MedicationRequest] MR
with [Medication] M such that MR.medication = M.reference() and M.code ~ "aspirin 325 MG / oxycodone hydrochloride 4.84 MG Oral Tablet"
//X.<reference>.references(Y) <=> X.<reference> = Y.reference()
define TestMedicationRequest1B:
[MedicationRequest] MR
with [MR.medication -> Medication] M such that M.code ~ "aspirin 325 MG / oxycodone hydrochloride 4.84 MG Oral Tablet"
define TestMedicationRequest1C:
[MedicationRequest] MR
let M: singleton from ([MR.medication -> Medication])
where M.code ~ "aspirin 325 MG / oxycodone hydrochloride 4.84 MG Oral Tablet"
Bryn Rhodes (Mar 24 2021 at 21:42):
But the engines don't support those capabilities (.resolve() and .reference() as well as the use of related-context retrieves in that way) (yet).
Aziz Boxwala (Mar 24 2021 at 22:14):
Bryn Rhodes said:
Aziz Boxwala , on that example of "Encouters for Diabetes", do you also want to consider Encounters that have a "diagnosis" element referencing a diabetes condition?
Not needed @Bryn Rhodes . Thanks though.
Last updated: Apr 12 2022 at 19:14 UTC