Finding Patients seen by clinicians

So I got an interesting email yesterday.

Someone asked me how to fulfill the following User Story: As a clinician, I want to search for a list of patients being seen by certain consultants today.

There were some Acceptance Criteria given:

  • I can enter the name of one or more consultants to search against, combining this with any clinics, wards and specialties that have been specified in the search criteria
  • I can amend a search by removing an item from the search criteria
  • In the list of results, I can see the following properties for each patient:
  • Hospital Number
  • NHS Number
  • Full name (surname, first name)
  • DOB
  • Sex
  • Consultant
  • Location (ward or clinic name)
  • Date (admission/appointment date)

Now, we’d want to dig a bit into the specifics of how some of the searches should work – eg what does it mean when you specify a consultant and a ward – that the consultant saw the patient on the specified ward on that date? And what happens when both a consultant and a specialty are in the query parameters?

But lets start with a simple case – getting a list of patients seen by a consultant on a specified date. This is not quite as simple as it sounds!

First off, lets think about the data model – how the data is represented on the server – and make some assumptions.

How do we know that a clinician has ‘seen’ a patient? I’m going to go with the idea that every clinician/patient interaction generates an Encounter resource, which means that a single hospital visit will have many Encounters – perhaps grouped under an EpisodeOfCare or a parent Encounter (each individual encounter will refer back to its parent using the Encounter.partOf property). There are other ways we could do this, but it’s something to work with for now.

The encounter has a reference to both patient and consultant (a participant of type ‘Practitioner’) as well as a reference to Location, so assuming we can get the list of encounters over the required date range, we should be able to get all the data we need:

Hospital Number. Depends a bit on what the hospital number is. If it’s a number assigned by the hospital for this admission, then we could use Encounter.identifier We may need to get this from the referenced ‘parent’ encounter via the .partOf property or the EpisodeOfCare. If it’s assigned to the patient, then we’d use Patient.identifier

NHS Number. Patient.identifier

Full name (surname, first name). Patient.name

DOB. Patient.birthDate

Sex. Patient.gender

Consultant. Encounter.participant.name as the participant is a reference to a Practitioner resource. You’d want to look at participant.type to get the consultant – as opposed to any other participants in this encounter.

Location (ward or clinic name). Encounter.location

Date (admission/appointment date). Encounter.period This is the date of the encounter of course. If you wanted the date they were admitted then you’d have to backtrack in the same way as we did for hospital number

Heres a picture of the model:

encounter

Now to think about what the queries are going to look like.

To work through this, I used clinFHIR to generate some sample data for me. From the main menu of clinFHIR select the resource builder option, then one of the sample patients (or you could add a new patient or select any other existing one).

From the ‘Core resource definitions’ dropdown at the top, select the Encounter resource. You should see a screen like this:

Screen Shot 2015-07-11 at 8.47.54 am

If you click on the datatype against an element you’ll get a simple data entry box on the right hand side. The minimum values you’ll want to set are:

Status. This is a mandatory field. ‘in-progress’ is probably the best value

Period. It’s important to set both start & end dates here, or the date search gets a bit wonky. (Here is where a profile would come in handy – this would enable you to specify that period is mandatory and both start & end are also required. ClinFHIR doesn’t support this level of detail – yet).

Participant. This loads a ‘child’ set of properties – the one you want to set is individual – the type Practitioner seems most appropriate. When you do select this, you’ll find that there is a link on the right side called ‘Search for Resource’.

Because we’re adding a reference to an existing resource we need to find it. Clicking on the link brings up a search screen (this is automatically generated from the server conformance resource) where we can enter our search criteria. There is a Practitioner with a name of ‘seven’, but you can select any one you want.

Note that to return to the main part of the resource, click on the ‘encounter’ in the bread-crumb at the top of the list of list of properties.

Location. This works in the same way as Participant as it’s also a complex reference to an external resource. Note how the search screen options have changed to suit the resource type. There aren’t many location resources, so just do a query with no filters and select any one.

Note that clinFHIR automatically adds the patient reference for you.

Oh, and if you’re part way through entering an encounter and want to create, say, a new Practitioner then clinFHIR supports ‘parking’ a partially completed resource. Just select the ‘Park Resource’ button at the lower right, then create your new Practitioner and save in the usual way. You can then retrieve the parked encounter from the toolbar at the top and continue on – the new practitioner can be found using the usual search.

Here’s what the screen looks like after all the data has been entered. You can see the resource you’re building as you go.

Screen Shot 2015-07-11 at 8.51.47 am

Once you’ve entered all the data, click ‘Save resource’ button at the lower right to save the resource to the server (actually Grahames server at http://fhir-dev.healthintersections.com.au/open/ ). You should get a confirmation that the resource has been saved – including the complete Url of the resource (I quite like to make a note of the Id – helps with finding things out later on, especially when things don’t quite work out as expected).

You’ll probably want to create 2 or 3 encounters for different patients on the same date.

So now that we have some sample data, how do we retrieve what we need?

Well, here’s where a REST client comes in really handy. I use POSTman (there’s a description of using it here – but do note that this was on DSTU-1 so the details of FHIR have changed) but there are plenty of other options.

The following query will return all encounters for a particular period – in this case on the 1st of July, 2015:

http://fhir-dev.healthintersections.com.au/open/Encounter?date=>2015-07-01&date=<2015-07-03

Date searching can be tricky. Heres the link in the spec for more detail. And this is why we were careful to specify a beginning and end date in our encounter period. An ‘open’ period (start only) would be included in any date search after that – most confusing!

And once you have the list of encounters, you have the links to the other resources (Patient, Practitioner, Location) and can get them directly. In fact, you can even get them included in the initial query using _include. Try this:

http://fhir-dev.healthintersections.com.au/open/Encounter?date=>2015-07-01&date=<2015-07-03&_include=Encounter.participant.individual

Now the returned bundle also contains the Practitioner resources that the matching encounters refer to. Neat huh?

Not satisfied? You want the Patient as well? No problemo:

http://fhir-dev.healthintersections.com.au/open/Encounter?date=>2015-07-01&date=<2015-07-03&_include=Encounter.participant.individual&_include=Encounter.patient

Not all servers will support _include – as you can imagine it’s rather complex for a server to implement, but if not then you can always query for them directly. The servers conformance resource is where you can find out what aspects of _include – if any – a server supports.

So far we’ve filtered on date – so we’ll get back all the encounters for that date range. We can extract the Consultants (participants) client side easily enough, but what if we wanted the encounters for a single consultant? We could also filter client side, but it’s more efficient get the server to do it. Try this:

http://fhir-dev.healthintersections.com.au/open/Encounter?participant=13

That will return all the encounters for a given participant Id – ie consultant. It pre-supposes that we know the id of the consultant (Practitioner) but that’s a simple thing to find out. Note that in the interest of clarity the other query parameters are not included here, but you can mix and match as much as you need to to refine your query.

There’s more in the spec on filtering on referenced resources here, and on chaining (which allows you to step further into the referenced resource when filtering).

So I think that’s enough for now. Hopefully this should be enough to get you started in your own exploration! The key take-aways:

  • Decide what your data model is going to be – at least a first cut.
  • Use clinFHIR to create sample data for you
  • Use Postman to run sample queries against Grahames server (as that is where clinFHIR saves the resources) so you can see how it all works – and this might cause you to go back and change the model – iterative development is good.
  • Refer frequently to the spec – especially how searches

One thing we haven’t talked about here is profiling resources – especially extensions for data items you need that aren’t on the base resource. A topic for another post perhaps.

FHIR and the associated tooling is now at the stage where the users of clinical systems – clinicians, admin staff and others – as well as business analysts can start to understand what it offers when it comes to recording and sharing clinical information, and to put their experience and knowledge back into the spec thereby making it even more fit for purpose.

Note that the links above are to test resources I created while writing this post – the resources themselves will be removed when Grahame next clears his server, but hopefully the syntax is pretty evident (if not, check the spec)

And finally, clinFHIR is very much a work in progress – there will be bugs and omissions so contact me if you come across anything weird.

Addendum: So Grahame pointed out that I didn’t quite go far enough in my examples. I talked about chaining, but didn’t use it where it would make sense. When I was finding Encounters for a participant I used their ID. However by using chaining, I don’t need to look up the Id of the Practitioner first. Instead of

http://fhir-dev.healthintersections.com.au/open/Encounter?participant=13

I can use

http://fhir-dev.healthintersections.com.au/open/Encounter?participant.name=seven

or using the identifier of the Practitioner (which is likely to be more accurate in practice) this becomes:

http://fhir-dev.healthintersections.com.au/open/Encounter?participant.identifier=http://hl7.org/fhir/sid/us-ssn|333333333

Thus the whole thing – returning all the encounters, plus any referenced Patients & Locations for a particular Practitioner over a given date range becomes:

http://fhir-dev.healthintersections.com.au/open/Encounter?date=>2015-07-01&date=<2015-07-03&participant.identifier=http://hl7.org/fhir/sid/us-ssn|333333333&_include=Encounter.participant.individual&_include=Encounter.patient

Who needs SQL?

About David Hay
I'm a Product Strategist at Orion Health, Chair emeritus of HL7 New Zealand and co-Chair of the FHIR Management Group. I have a keen interest in health IT, especially health interoperability with HL7 and the new FHIR standard.

One Response to Finding Patients seen by clinicians

  1. Pingback: Building resources from FHIR profiles. | Hay on FHIR

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: