FHIR searches and bundles
Query FHIR servers with parameters, operators and sorting - the client pages through the result bundles for you.
You can query FHIR servers with search parameters, operators, sorting and paging - the client builds the query URL and unwraps the results for you. A server answers every search with a Bundle, a container resource that holds the matches, the total number of them and links to further pages.
Build a search
The resources method of a connection client returns a lazy search object. Each call below refines the query and the server receives nothing until you fetch the results.
# -*- coding: utf-8 -*-
# Zato
from zato.server.service import Service
class FindPatients(Service):
name = 'demo.fhir.find-patients'
def handle(self) -> 'None':
client = self.fhir['FHIR.Sample']
# Everything about patients starts here
patients = client.resources('Patient')
# Active patients named Chalmers, at most 10 of them, youngest first
result = patients.search(name='Chalmers', active=True).sort('-birthdate').limit(10)
# Only now is the server invoked
for patient in result.fetch():
self.logger.info('Found %s', patient['name'])
Invoking the service writes each match to the server log:
Search operators
Search parameters accept operators appended with a double underscore, mirroring what the FHIR specification allows in URLs:
# Born in the year 2000 or later - birthdate=ge2000-01-01 on the wire
patients.search(birthdate__ge='2000-01-01')
# Name containing a string
patients.search(name__contains='alm')
# Status being none of the listed values
observations = client.resources('Observation')
observations.search(status__not=['cancelled', 'entered-in-error'])
Python-style underscores in parameter names are translated to FHIR-style dashes automatically, e.g. general_practitioner becomes general-practitioner.
Fetch the results
There are several ways to obtain the results, depending on how much data you expect:
# One page of results, as configured with .limit
found = result.fetch()
# All the results - the Bundle's next links are followed until there are no more pages
found = result.fetch_all()
# The same, but lazily - each page is fetched only when the iteration reaches it
for patient in result:
...
# A single match - raises an error if there are none or more than one
patient = patients.search(_id='511a6231-361e-4b8e-8f9c-b183b7813f4d').get()
# The first match or None
patient = patients.search(name='Chalmers').first()
# Only the number of matches, without any resources
how_many = patients.search(active=True).count()
Read the Bundle itself
To read the Bundle's own fields, e.g. its total or its links, use fetch_raw:
bundle = result.fetch_raw()
self.logger.info('Total matches: %s', bundle.total)
for entry in bundle.entry:
self.logger.info('Entry: %s', entry.resource)
Include related resources
A single search can return related resources in the same Bundle, e.g. each Encounter together with the Patient it refers to, saving you the extra round trips:
# Encounters plus the patients they point at ..
encounters = client.resources('Encounter').include('Encounter', 'subject')
# .. or, the reverse, patients plus the observations that point back at them.
patients = client.resources('Patient').revinclude('Observation', 'subject')
Select fields to transfer
To reduce the amount of data transferred, ask the server for specific elements of each resource:
# Each returned Patient will contain only its name, plus the id and resourceType fields
patients.elements('name').fetch()
Conditional operations
Searches can also drive writes - the search parameters then act as the condition:
# Create the patient only if no resource matches the search
patient = client.resource('Patient', identifier=[{'system': 'urn:mrn', 'value': '12345'}])
search = client.resources('Patient').search(identifier='urn:mrn|12345')
patient, created = search.get_or_create(patient)
self.logger.info('Newly created? %s', created)
See also
| Page | What it covers |
|---|---|
| Resources | Create, read, update and delete any FHIR resource |
| Path access | Values extracted from search results in single calls |
| Connections | The Dashboard form and everything self.fhir accepts |
Learn more
Schedule a meaningful demo
Book a demo with an expert who will help you build meaningful systems that match your ambitions
"We evaluated 12 integration platforms and Zato was the only one to score 100%."
Philip Zuñiga, Assistant Professor, University of the Philippines