Adventures in FHIR Searching: Getting a list of patients in a Ward
October 24, 2013 Leave a comment
Had an interesting set of exchanges on the implementers skype chat yesterday talking about searching in FHIR.
The background was that we are looking at building a tablet app to support the recording of medication dispensings. Orion has an application (a Hospital Information System or HIS) that records this using a desktop interface, so the plan is to build a FHIR server that will act as a ‘proxy’ between the HIS and the tablet, with the tablet app consuming JSON FHIR resources over a RESTful interface.
We are thinking that the user will log into the tablet, then get a list of the wards they are currently scheduled on. They will select a ward, which will give them a list of patients, then select the patient from which they will get the medications to administer (or a similar type of workflow). I was asked to help out with the design of the FHIR resources & calls – and started to think about how to get as far as the patient list (I’ll consider the medication administration stuff later).
Looking through the current FHIR resource list I found a Location resource that specifically mentions that it models a Ward, so my first thought was to add an extension to that resource of type List, and then the List could reference a collection of Patients. The proxy server would be responsible for communicating with the HIS and constructing the bundle of these resources, which could be returned to the tablet app on request.
I mentioned this on the skype chat, and after some discussion with Grahame and Lloyd, we figured that a better solution would be to model the relationships using an encounter, and then we could do a FHIR query to get the data we need, using an _include parameter on the query for efficiency (I’ll get to this later).
So the relationship between the resources is like this:
Our approach will be:
- get the ward we want
- then get the encounters that are associated with that ward
- and then we can get the patients from the encounter.
Getting the ward is a straight forward query. Suppose the name of the ward is ‘Ward1’ then it’s a simple GET query against Location:
GET /Location?name=Ward1
Note that we will get back a bundle, and we may need to check for multiples – eg Ward1 and Ward11 would be valid matches (it’s a string search). We might also want to include a Location.type parameter if that is appropriate in our situation. But, we now have the Location resource– the Ward – and the ID of that resource. Let’s pretend the ID is 100.
Now to get the Encounters associated with that Location. Encounter does have a location property which is a sub-object with properties of Location & Period. In other words, an encounter can have many locations, and each location has a period over which the location was valid. This makes sense of course, as a patient can be moved around different places (Wards, radiology, therapy etc). So, we want encounters that are associated with our specific Location (Ward) right now. (There are other subtleties, but let’s keep it simple for now). We’ll assume that if there is a Location that matches ours, and where the period.end property is not present then that means they are currently associated with our ward.
However, there is a problem: There is no search parameter defined for location against Encounter – and in fact we need 2 of them – one for the location.location property and one for the location.period property. There are 2 things we can do:
- Petition the FHIR team to add these parameters
- Make these search parameters that our server supports (which is quite legitimate, though does mean our query on’t work on other servers)
We will do both. We will define 2 search parameters:
- location that matches Encounter.location.location (which is a reference)
- location-period that matches Encounter.location.period (which is a date).
and also ask the core team to add them (actually it is the HL7 committee that has oversight of this resource – you can look this up from this page, but sending a message to the core team via any of the supported channels will achieve this).
So now we have:
GET /Encounter?location =100 &location-period => 25-10-2013
(assuming that the date today is 25th October 2013)
So, now we have the encounters we want – all we need are the patients.
We could make a query for each patient – we can get that from Encounter.subject – but we can also ask the server to do that in our query by using the _include parameter. This is an instruction to the server to include the referenced resources in our query as well as the directly matched resources. So our complete query is:
GET /Encounter?location =100 &location-period => 25-10-2013&_include=Encounter.subject
will return a bundle that will contain all the encounters currently associated with Ward1 (resourceID=100), plus all the patient resources that are in these encounters. Job done!
Some notes:
- We have defined some server specific parameters. Should the committee decide not to add these parameters to the spec, then either we accept this (after all we’re only concerned with our server at the moment anyway), or we could re-jig the query. Another exercise for the reader…
- Servers are not obliged to support all search parameters – even if they are named in the spec. If we wanted our client to be able to talk to another FHIR server, then we would need to examine its conformance resource to make sure it does.
- Servers are also not obliged to honour the _include parameter. If they don’t, then it simply means that we have more work to do client side – we just make direct requests for each patient after we retrieve the encounters.
- In an earlier version of this post I was querying ‘into’ search parameters – eg GET /Encounter?location.period=… – it doesn’t work like that – it’s not like a path. Part of the issue is that we can’t have ‘ad-hoc’ queries into resources – to quote Grahame: we’ve agreed that clients can’t simply launch random queries into the content of the resources – it has to be pre-agreed fields – there’s no way for the server to make that efficient, except in the case of special technologies
- Date querying is complicated. There’s a whole section in the spec on it.
This became a rather longer post than I intended, but hopefully it is a useful exercise to run through the thinking behind what became quite an elegant query – and I learned a lot doing it. It’s not the only way to do it of course, but it was a fun process!
Recent Comments