FHIR Chat · Retrieving FHIR contained resources · cql

Stream: cql

Topic: Retrieving FHIR contained resources


view this post on Zulip Michael Riley (Aug 01 2019 at 14:12):

Hey CQL team. Is there a mechanism to retrieve information from contained resources from a query request. Something like define "Aspirin MedRequests" [MedicationRequest: medication.code in "acetylsalicylic acid"] if the MedicationRequest has a medication reference set?

view this post on Zulip David Hay (Aug 03 2019 at 19:29):

does this help: http://hl7.org/fhir/search.html#contained

view this post on Zulip Chris Moesel (Aug 05 2019 at 14:01):

Hi @Michael Riley -- if you strictly adhere to the defined FHIR models in CQL, then I think the only valid approach is via a subquery. It's more complicated (and less efficient) than I prefer, but I think it's the only way that will work using a strict interpretation of the model. Here is an example of your expression using that approach (and supporting both medication as a code and as a reference):

define "Aspirin Medications":
  [Medication: "acetylsalicylic acid"]

define "Aspirin MedRequests":
  [MedicationRequest] R
  let
    MedCode: FHIRHelpers.ToConcept(R.medication as FHIR.CodeableConcept),
    MedRef: (R.medication as FHIR.Reference).reference
  where
    MedCode in "acetylsalicylic acid"
    or exists (("Aspirin Medications") M where M.id = MedRef or EndsWith(MedRef, '/' + M.id))

Note: I haven't tested the above in a run-time environment, but it does compile w/ CQL-to-ELM.

view this post on Zulip Chris Moesel (Aug 05 2019 at 14:04):

That said, I have seen cases where authors have treated the default membership operator for MedicationRequest as if it is a FHIR query on MedicationRequest.medication -- in which case you can just use `[MedicationRequest: "acetylsalicylic acid"]. But this is not the standardized model, so it would require special support from the execution engine (and you would need to make sure the CQL-to-ELM is not in strict mode). If you want your CQL to be portable and to work across various execution environments, I wouldn't recommend that approach.

view this post on Zulip Chris Moesel (Aug 05 2019 at 14:06):

Last, @Bryn Rhodes is working on something called QUICK FHIR (or something like that). It's an alternate, simpler to use, FHIR model for CQL. I think it may abstract these sorts of issues from the author -- but you'd need to talk to Bryn to get the details.

view this post on Zulip Michael Riley (Aug 05 2019 at 15:33):

Wow this is exactly what I was looking for. Although it seems like you need to pull the medication resource set from a previous query, before getting the medicationrequest resource. We might have MedRequests with a heterogenous set of CodeableConcepts vs Refences here. I assume that casting with the 'as' command fails silently in the cases where it's not relevant?

view this post on Zulip Chris Moesel (Aug 05 2019 at 15:49):

You can put the medication resource set subquery in the same query, but I think it would be less efficient in some execution implementations:

define "Aspirin MedRequests":
  [MedicationRequest] R
  let
    MedCode: FHIRHelpers.ToConcept(R.medication as FHIR.CodeableConcept),
    MedRef: (R.medication as FHIR.Reference).reference
  where
    MedCode in "acetylsalicylic acid"
    or exists ([Medication: "acetylsalicylic acid"] M where M.id = MedRef or EndsWith(MedRef, '/' + M.id))

The as expression will result in null if the actual type does not match the cast type. See: https://cql.hl7.org/03-developersguide.html#casting

In CQL, nulls tend to propagate, so often it ends up working the way you want in cases like this.

For example, if a MedicationRequest instance has a medicationReference, then MedCode will be null -- and since null in "acetylsalicylic acid" results in null, that first part in the where clause will not be satisfied (which is right).

Similarly, if a MedicationRequest instance has a medicationCode, then MedRef will be null -- and since M.id = null will always result in null and EndsWith(null, '/' + M.id) will also always result in null, that 2nd clause in the where will never be satisfied when MedRef is null (which is also right).

view this post on Zulip Michael Riley (Aug 05 2019 at 16:18):

This is awesome thank you so much! Makes perfect sense to me, it's just CQL that's way more clever than I'm normally writing :)

view this post on Zulip Chris Moesel (Aug 05 2019 at 16:20):

It looks right to me, but like I said, I haven't fully tested it -- so let's hope it works! ;-)

view this post on Zulip Michael Riley (Aug 07 2019 at 17:38):

I was able to have this evaluate for medicationRequest, but what do I do in the case of a list of references? For example, what if I want to compare an Encounter's diagnosis reference to a set of conditions I've allready pulled?

define "ChlamydiaDiagnosis": [Condition: Code in "Chlamydia_Codes"]
define "ChlamydiaEncounters":
[Encounter] Encounters
where exists ("ChlamydiaDiagnosis" cond EndsWith(Encounters.diagnosis.condition.reference, '/' + cond.id))

This line returns an error of

 Error [16:1]: Expected a list with at most one element, but found a list with multiple elements.

Since Encounter.diagnosis.condition.reference is a list of references, instead of a singular reference, how do I splay out that list to be used in this context? I think I use the ForEach evaluator, but I can't find a good example of how to use it.

view this post on Zulip Lloyd McKenzie (Aug 07 2019 at 17:49):

@Bryn Rhodes

view this post on Zulip Chris Moesel (Aug 07 2019 at 17:55):

@Michael Riley and @Bryn Rhodes -- I'm already in the middle of working this out. Stand by.

view this post on Zulip Chris Moesel (Aug 07 2019 at 18:06):

@Michael Riley -- this can actually be accomplished using a single query and the with construct:

define "ChlamydiaEncounters":
  [Encounter] Encounter
    with [Condition: code in "Chlamydia_Codes"] ChlamydiaDiagnosis
    such that exists (
      (Encounter.diagnosis.condition.reference) ref
        where EndsWith(ref, '/' + ChlamydiaDiagnosis.id)
    )

This essentially says to query over each encounter and each chlamydia condition, looking for encounters such that it's dx reference ends with a chlamydia condition's id.

For more on the with construct: https://cql.hl7.org/02-authorsguide.html#relationships

view this post on Zulip Chris Moesel (Aug 07 2019 at 18:09):

The subquery actually needs to use the encounter refs as its source, since they are a list within a single encounter. Since we use with on the chlamydia conditions, we don't need to worry about the "listness" of the conditions, as the iteration over that is built into the with construct.

view this post on Zulip Michael Riley (Aug 07 2019 at 18:21):

@Chris Moesel Thank you so much, this worked for me. I didn't really understand the with clause very well.
I know the retrieve evaluator doesn't have a great mechanism for doing this, but if we could have the retrieve evaluator use either references, or construct a reference from a resource, that would be incredible.
Simply put, being able to do something like
define "ChalmydiaEncounters":[Encounter: diagnosis references "ChlamydiaDiagnosis"]
to just pull resources that link against other resources would be really big for these non-patient-links. FHIR has some robust querying capability, I feel like CQL isn't leveraging it to the fullest.

view this post on Zulip Chris Moesel (Aug 07 2019 at 18:30):

Hey @Michael Riley -- agreed that something like that would be way cool. One of the reasons that CQL doesn't leverage all of FHIR is that CQL is built to be data model agnostic. It needs to support any data model, not just FHIR -- so building in FHIR-specific features wouldn't really support that aim. That said, alternate data models could be designed that are based on FHIR but expose properties in a way that makes traversing references and leveraging queries easier. I don't know if @Bryn Rhodes has any of the in mind for QUICK FHIR, but I'm tagging him just in case.

view this post on Zulip Michael Riley (Aug 07 2019 at 18:42):

Yeah, I completely understand the independent data model complication. It's pretty brilliant that the java engine can rely on commonly used interfaces like "iterable" to help facilitate the execution engine, or resolve a type. However, a referencing relationship seems like something everyone would want. Everyone's using a database, almost everyone's database is relational. Some way to explicitedly call out to those relations would be useful.

view this post on Zulip Bryn Rhodes (Aug 08 2019 at 22:10):

@Michael Riley , this is an area that we've spent a lot of time thinking about, but there are several potential ways it could be addressed, all with different levels of effort in different areas of the spec/tooling, and different resulting impacts on the implementation.

The most transparent way would be to actually use the ELM to detect these types of patterns when they are used within a given expression and within the data provider actually support a kind of rewrite that would push the "include" into the request and transform the "child retrieves" into a reference to a materialized result of the child retrieve. This approach, as you can imagine, would require a fairly sophisticated provider, but it's possible without any change to the translator or the model info. As a con, it does require authors to use certain patterns to access data.

As Chris alluded to, we've also considered how we might make this transparent behind the model. The idea is that for reference-valued elements in FHIR, the model info element would be class-valued, rather than reference-valued, and it would be up to the data-access layer to resolve that (typically by fetching the instance pointed to by the reference, but you could imagine a more sophisticated implementation along the lines of the previous approach as well).

These are just potential approaches at this point though, because they require quite a bit of effort to really get working. We have taken steps towards it though in the latest STU with the introduction of RelationshipInfo. Now the model can at least describe how classes in the model are related to eachother.


Last updated: Apr 12 2022 at 19:14 UTC