In this module, we will go through some more advanced ways of searching. This module assumes you have basic knowledge on searching. If you prefer to start with the basics, please go through the Search operations and parameters module first. In the exercise of this module, we will run queries on our own Vonk server. The end-point of this server is http://vonk.fire.ly
The topics covered in this module are:
Chaining allows you to search on properties of a referenced resource. This means that you can go through a graph of connected resources and get back a result by using search parameters defined for the last resource type in a chain.
To illustrate how chaining works in practice, let's go through an example. An Observation contains a reference to a Patient resource in the
subject element. The search parameters
subject allow you to filter Observations on a specific subject (the difference being that the
patient search parameter is restricted to the resource type Patient, while the
subject search parameter searches for all resource types that can be the subject of the Observation). Now suppose you want to filter the Observations based on properties of the Observation's subject. To do so, you would only need to append the search parameter (e.g.
patient) with a
. followed by a valid search parameter for the referenced resource (e.g.
For example, to search for all Observations from Patients born since the 1st of January 2001, you would get:
Note that you could also use the
subject search parameter, but in this case, you will still need to specify the resource type that you are looking for. It's not allowed to address multiple resource types at the same time (correctly implemented FHIR servers will reject searches in which this is the case).
The correct syntax for the same search based on the
subject parameter is as follows:
Without chaining you would have needed multiple search requests to perform this search:
It would be nessesarry to do some kind of filtering and processing on the client side.
Please note, you can only chain search parameters of the type
reference that point to elements of type
Reference.reference. In FHIR, references using so-called logical references (using
Reference.identifier) are also allowed. However, because a FHIR Server cannot reasonably verify that the resources behind these references exist, chaining on these elements are not supported.
Chaining can be very efficient as you can cross more than one resource in a single chain. For example, try to search for all Observations based on a MedicationRequest for a Medication that contains the ingredient Lorazepam (substance):
Note that except for the last parameter, all parameters are of the type
Instead of filtering resources based on properties of referenced resources, it's also possible to filter resources based on properties of resources referring to them. For example, you may want to select all Patients having an appointment today. In this case, you would need to use the
_has parameter followed by:
date) and the comparison value
These parts are separated by a
:. The correct syntax of this search would be:
Let's make it a bit more complex. Say you want to select all Patients having an Observation performed by a specific Organization, let's assume the identifier of this Organization is
It's also possible to add more than one
_has parameter to your search. But be aware that this would result in a joined set of two independently executed
_has queries. For example, the following query:
will not result in a list of Patients having an appointment with Practitioner
1234 today. Instead, it will return all Patients having an appointment today as well as all Patients having an appointment with Practitioner
1234 at any point in time.
A _filter expression can be used for more advanced searches in which multiple queries need to be combined. _filter provides a range of advantages compared to the regular way of using search parameters:
For example, you could use a filter to select all Patients from Organizations
1235 with inactive records.
GET [base]/Patient?_filter=active eq false and ( organization eq 1234 and organization eq 1235 )
Note that this expression is equivalent to:
It gets more challenging when you want to combine these queries with an
or. For example, when you want to select all Patients with an inactive record as well as all Patients from Organizations
1235 you will definitely need a filter.
GET [base]/Patient?_filter=active eq false or ( organization eq 1234 or organization eq 1235 )
Would you have tried to define this expression as following:
The server would interpret this as a search for Patients where the value of
active is either 'false', 'organization=1234' or '1235', which is obviously not what we try to achieve.
All search parameters that are normally defined for resources can be used in a _filter expression.
Additionally, negated expressions can be used in a filter search request. This feature can otherwise only be achieved with the
:not modifier for token search parameters.
For example, the following search request retrieves all Patient resources which contain a different name than "Sarah":
GET [base]/Patient?_filter=name ne Sarah
Another powerful search function is the compartment search. The syntax of a compartment search is as follows:
Adding search parameters to a compartment search is optional. To return all resources in a compartment use a
* instead. For example, use the following request to select all resources that have any reference to the Patient with id
You can also define the types of resources you want to retrieve using the
_type parameter. For example, the following request will return all Observations and Encounters of the Patient with id “1234”.
Finally, you can add additional criteria to your compartment search. Let's say you want to retrieve all Observation resources that contain a reference to the Patient with the logical id
1234 and which have the observation status set to final. The following requests, of which the first one is the compartment search, are both valid and will produce the exact same results.
GET [base]/Patient/1234/Observation?status=final GET [base]/Observation?subject=Patient/1234&status=final
Composite search parameters are parameters that take a combination of values to evaluate. For example, the composite search parameter
component-code-value-quantity evaluates Observations against a pair of values for the elements
valueQuantity. The values are separated by
$. The request given below returns all Observations with the given LOINC code and a value greater than 80kg.
Note that this search would be equivalent to the following request using the
value-quantity search parameters:
The power of composite search parameters becomes more clear in the following examples based on the composite search parameter
characteristic-value, which searches for the pair of values for
GET [base]/Group?characteristic-value=gender$mixed GET [base]/Group?characteristic-value=gender$mixed,owner$peter
The first one returns all Groups where the gender is mixed. In this case using the parameters
value (e.g. characteristic=gender&value=mixed) would not return the same results. Groups having the characteristic gender and the value female and having the value mixed for another key would be returned as well.
The second one returns all Groups where gender is mixed as well as groups where the owner is peter. These kinds of searches would be impossible to express without composite search parameters.
Sometimes it can be useful to include related resources in your search results. For example, when you search for Observations, it can be useful to include the Patient resources that are subject of the returned Observations.
GET [base]/Observation?_include=Observation:patient GET [base]/Observation?_include=Observation:patient&patient=1234
The first request returns all Observations and the related Patient resources. The second one returns all Observations for a specific Patient with id=1234 as well as the Patient resource itself. It is possible to include multiple related resources by repeating the
Instead of adding resources that are referenced from the returned resources in your search results, you may also want to add resources that refer to them. For example, when you are searching for Patients, you may want to add Observations and Conditions that have a reference to these Patients in their
subject fields. The request below returns a specific Patient (the Patient with id=1234) and includes all Observation and Condition resources of this Patient in the search Bundle.
A revinclude may come in handy in combination with a reverse chaining expression. You can get back the resources due to which the matches of the reverse chaining where included in the search results:
The include and revinclude process can be recursive. With a
:recurse modifier, resources can be included based on parameters defined for resources that were included through a different _include or _revinclude expression:
FHIR provides a set of operations that can be invoked on the base endpoint, a resource type, a resource instance or a specific version of a resource instance. Usually, operations are invoked using a POST request, but in some cases, a GET request is allowed as well. To invoke an operation its name should be prefixed with a
$. Below is an example of an operation that retrieves all resources related to Patient with ID=1234. Note that this is similar to a compartment search.
The body of a request invoking an operation often contains a Parameters resource to specify the in parameters of the operation. For example, in the
everything operation optional start and end dates can be provided. The body may also contain other resources, for example, the resource you want to validate by using the
Operations can be resource specific or apply to all resource types. In the last case, we speak about base operations. It is also possible for implementations to define their own operations using the OperationDefintion resource.
One operation that is often used is the
validate operation. Let's say you want to validate a Patient resource against the daf-patient profile. You could do so by running the following request and adding your Patient resource in the request body.
ValueSets are often composed of codes from other ValueSets or CodeSystems by using include and exclude filters. As you will learn (or already have learned) in the [Terminology] module, ValueSets contain both a
compose element, which is used to create a ValueSet, and an
expansion element, which can be used by a FHIR Terminology server to return all codes in a ValueSet. Below are a couple of example requests.
GET [base]/ValueSet/1234$expand POST [base]/ValueSet/$expand POST [base]/ValueSet/1234/$expand
The GET request can be used when a ValueSet is already known to the server. When a POST request is used, the request body contains a Parameters resource in which one or more in parameters are defined. The Parameters may include the ValueSet resource or contain a canonical url of an existing ValueSet. The returned result of the
expand operation is the expanded ValueSet resource. Note that the expansion can change over time depending on changes in included ValueSets and CodeSystems.
Nictiz is the centre of expertise for standardization and eHealth in The Netherlands. HL7 Netherlands core and MedMij profiles are published on Simplifier. MedMij is a national project that aims to give Dutch citizens integrated access to all their health data in one personal health environment. FHIR is used as a standard to exchange health information between the involved parties. The profiles are based on standardized clinical building blocks called Health and Care Information Models (HCIM).
The Implementation Guide of Nictiz contains a section called 'List of invocations' in which examples are given on how the data can be retrieved using the Dutch national FHIR model.
Castor EDC is a company that supports researchers in collecting data for medical research. The Castor EDC application is linked to the electronic health record of the hospital, in which the researchers can mark his or her patients for inclusion. We implemented a Vonk Facade server for Castor EDC in a university hospital in the Netherlands, which maps the data from their clinical data warehouse to FHIR resources and sends them to the Castor EDC application. In the first pilot, three resources were implemented: Patient, Observation and Condition.
The Castor EDC application needs to be able to retrieve all resources from a specific Patient. The
revinclude functions are supported in the implementation and can be used to retrieve a specific Patient including all Observations and Conditions referring to this Patient in the subject field.
Note that in this query it's only possible to filter on search parameters implemented for the Patient resource. Researchers should however be able to filter Observations and Conditions on date. To do so, a more complex query is required. For example, to retrieve a specific Patient (let's assume the id of this Patient is 'example') as well as all his/her Observations since January 2018, the following query can be used.
In this exercise you will run some advanced search requests. You may either use a REST client like Postman to run your requests or paste them directly in your browser. Start by reading the case description. Here below are a couple of links that you may find useful during this exercise:
Either try out these searches yourself or follow the steps below to get to formulate the right search request. In this exercise we assume you use the public Vonk server, but you may use any FHIR server you want. Note however that not all search functionalities may be implemented in all FHIR servers.
We are always looking for ways to improve our products. The Profiling Academy was built using our own IG-editor in Simplifier. If you have any feedback on this module or on our Profiling Academy in general, please leave a comment in the Issue Tracker of the project.
Follow one of our predefined or tailor-made courses. We will make sure you know FHIR inside-out.
Powered by SIMPLIFIER.NET