FHIR Chat · Repeating answers to a top-level question · questionnaire

Stream: questionnaire

Topic: Repeating answers to a top-level question


view this post on Zulip Josh Mandel (Sep 01 2021 at 16:21):

(Bonus points if someone can help point me to the relevant docs; I just spent ~20min trying to find this in guidance at http://build.fhir.org/questionnaire and http://build.fhir.org/questionnaireresponse.)

view this post on Zulip Josh Mandel (Sep 01 2021 at 16:30):

/poll Let's say I have a Questionnaire with a single question ("tell me the name of a color you like"), and it's marked as "repeats". Now, a user supplies answers indicating they like "Red", and "Green", and "Blue". Does the resulting QuestionnaireReponse...

view this post on Zulip Lloyd McKenzie (Sep 01 2021 at 17:02):

Looks like there isn't explicit guidance that says you can't do #2 - we never contemplated anyone would try. (The fact that QuestionnaireResponse.item.answer repeats I would have thought made the answer obvious.) Feel free to submit a tracker item.

view this post on Zulip Paul Lynch (Sep 01 2021 at 17:06):

I don't think that's obvious. In its internal (non-FHIR) format, for a string data type (i.e. not a list) that repeats, LHC-Forms would have three items for these three answers. LHC-Forms converts those on export to QuestionnaireResponse into a single item with multiple answers.

view this post on Zulip Josh Mandel (Sep 01 2021 at 18:11):

@Lloyd McKenzie are there circumstances where any of the following would not hold?


Top-level items with the same linkId

QuestionnaireResponse
  .item.where(value.exists())
  .linkId
  .isDistinct()

I'm guessing this is always true.


Sibling answer.items with the same linkId

QuestionnaireResponse
  .descendants()
  .answer
  .select(
      item
      .where(value.exists())
      .linkId
      .isDistinct())
  .allTrue()

I'm guessing this is always true?


Sibling item.items with the same linkId

QuestionnaireResponse
  .descendants()
  .item
  .select(
      item
      .where(value.exists())
      .linkId
      .isDistinct())
  .allTrue()

I'm guessing this is always true.


(As you can see, I'm thinking about how to formalize this, and trying to test my understanding at the same time. I suspect there's some interaction with item.type=group that I'm not quite grokking. I'm using .where(value.exists()) as a kind of proxy for question-type items, since the item type is only modeled in the Questionnaire, not surfaced in the QuestionnaireResponse.)

view this post on Zulip Josh Mandel (Sep 01 2021 at 18:35):

The definition of "repeats" today says:

An indication, if true, that the item may occur multiple times in the response, collecting multiple answers for questions or multiple sets of answers for groups.

but if I'm understanding Lloyd's answer to the poll correctly, then "collecting multiple answer for questions" is not a use case where the item will occur multiple times in the response (rather, the item will occur once and there will be multiple answers within it). I've submitted FHIR-33335 to start, but I don't understand enough to know what exactly to propose.

view this post on Zulip Lloyd McKenzie (Sep 01 2021 at 19:38):

If your root item is a group and it repeats, then there will be multiple items with the same link id at the root.

view this post on Zulip Lloyd McKenzie (Sep 01 2021 at 19:38):

Same is true at the non-root level

view this post on Zulip Lloyd McKenzie (Sep 01 2021 at 19:39):

It's only sibling questions that must have distinct linkIds.

view this post on Zulip Josh Mandel (Sep 01 2021 at 19:55):

Cool -- so I think the fhirpath I wrote above is all roughly correct, and if so can be lumped together in a constraint like:

QuestionnaireResponse
  .union(descendants())
  .select(
    item.where(answer.value.exists())
    .linkId
    .isDistinct())
.allTrue()

view this post on Zulip Josh Mandel (Sep 01 2021 at 20:02):

I've updated the issue to propose this in addition to language tweaks.

view this post on Zulip Paul Lynch (Sep 02 2021 at 00:01):

@Josh Mandel That doesn't look correct to me, for that case Lloyd mentioned of a repeating group. A QuestionnaireResponse that had two instances of a repeating group will repeat not just the group linkIDs, but the linkIDs of the answered questions within the group.

view this post on Zulip Paul Lynch (Sep 02 2021 at 00:02):

Example:

view this post on Zulip Paul Lynch (Sep 02 2021 at 00:02):

        {
          "linkId": "/54126-8/54137-5",
          "text": "Diseases history panel",
          "item": [
            {
              "linkId": "/54126-8/54137-5/54140-9",
              "text": "History of diseases",
              "answer": [
                {
                  "valueCoding": {
                    "code": "3982",
                    "display": "Abdominal pain"
                  }
                }
              ]
            }
          ]
        },
        {
          "linkId": "/54126-8/54137-5",
          "text": "Diseases history panel",
          "item": [
            {
              "linkId": "/54126-8/54137-5/54140-9",
              "text": "History of diseases",
              "answer": [
                {
                  "valueCoding": {
                    "code": "2315",
                    "display": "Back pain"
                  }
                }
              ]
            }
          ]
        }

view this post on Zulip Paul Lynch (Sep 02 2021 at 00:10):

(That example comes from https://lhcforms.nlm.nih.gov/sdc. After picking a form to view, you can choose "Show As"->"QuestionnaireResponse".)

view this post on Zulip Josh Mandel (Sep 02 2021 at 00:42):

I don't think the example you shared here would violate the constraint I proposed -- at least, I believe ".where(item.value.exists())" should effectively ignore any group-type items because they have no direct answers. Does this make sense, or am I still confused?

view this post on Zulip Paul Lynch (Sep 02 2021 at 00:45):

You called descendants(), which will pick up the children of the repeated group, namely the items with the same linkId that have answers.

view this post on Zulip Paul Lynch (Sep 02 2021 at 00:54):

But I think I misread your FHIRPath expression. I thought it was checking that all of the linkId for items with answers are distinct. Did you mean to put the isDistinct() inside the select(...)?

view this post on Zulip Josh Mandel (Sep 02 2021 at 00:58):

I am checking that the linked IDs for items that are sibling members of the same array and also have answers... are unique. I want this to be true for each items array, but not a cross them. In other words, for every item array "A" at any level of the hierarchy: look at just the items of A that have answers, and and sure their link IDs are unique within A.. That's why isDistinct() sits inside of the select.

view this post on Zulip Paul Lynch (Sep 02 2021 at 01:05):

Okay, that looks correct then. Sorry for the confusion. I should have tested it first.

view this post on Zulip Lloyd McKenzie (Sep 02 2021 at 03:11):

It's a hard expression to parse in your head :)

view this post on Zulip Josh Mandel (Sep 02 2021 at 13:18):

I'm very open to ideas for better ones. The main thrust is to capture what seems to be implicit knowledge of the rules in an explicit + computable fashion

view this post on Zulip Paul Lynch (Sep 02 2021 at 13:29):

@Josh Mandel Do you see any issue with replacing QuestionnaireResponse
.union(descendants()) with QuestionnaireResponse.union(repeat(item))? It avoids picking up a bunch of nodes that won't have items as children.

view this post on Zulip Josh Mandel (Sep 02 2021 at 13:34):

Won't that just find paths like .item.item.item and miss paths like .item.answer.item ?

view this post on Zulip Josh Mandel (Sep 02 2021 at 13:35):

There may be a variant of repeat(item | answer) that works though.

view this post on Zulip Josh Mandel (Sep 02 2021 at 17:46):

(QuestionnaireResponse | repeat(answer | item))
.select(
  item.where(answer.value.exists())
  .linkId.isDistinct())
.allTrue()

This works, I think.

view this post on Zulip Paul Lynch (Sep 02 2021 at 18:14):

Yes, that looks good. Another issue with descendants() is would pick up resources under "contains"-- so this is better.

view this post on Zulip Brian Postlethwaite (Sep 03 2021 at 01:41):

Fhirpath ninjas!


Last updated: Apr 12 2022 at 19:14 UTC