FHIRPath Expressions
Paths are defined using FHIRPath, which is an expression language defined by FHIR. In its simplest form, this can take the form of a single dotted path:
Patient.name.given
In the example above, the FHIRPath expression matches all of the patient's given names. If this path is used as the expression in a Custom Search Parameter, any values for the patient's given name(s) will be indexed by the search parameter.
Paths can also perform more advanced lookups. This page outlines expressions to satisfy various common needs, and includes example SearchParameters that use them.
When developing a FHIRPath expresion, the _fhirpath
parameter can be helpful. This parameter can be added to any FHIR REST URL where the response will be a resource or a Bundle resource containing a collection of resources (e.g. a FHIR Read or a FHIR Search). When it is present in the request URL, the parameter value will be parsed as a FHIRPath expression and then applied against the response resource.
For example, suppose you have a FHIR repository containing the following resource:
{
"resourceType": "Patient",
"id": "123",
"extension": [{
"url": "http://acme.com/eye-color",
"valueCode":"hazel"
}]
}
the following URL will fetch a resource with ID Patient/123
and then apply a FHIRPath expression against it. You can use this to test whether your expression returns the desired value from the resource in question.
http://localhost:8000/Patient/123
This will produce a result like the following if the expression is correct:
{
"resourceType": "Parameters",
"parameter": [ {
"name": "result",
"part": [ {
"name": "expression",
"valueString": "Patient.extension('http://acme.com/eye-color').value.as(code)"
}, {
"name": "result",
"valueCode": "hazel"
} ]
} ]
}
Another mechanism to test search parameter expressions is to create your search parameter as well as a resource that you want to index, and then perform a Reindex Dry-Run against your candidate. This shows all existing indexes and any that will be newly created by your search parameter.
This example indexes the value on a custom extension that is added to a resource. Note that the extension does not need to be declared anywhere (aside from in the SearchParameter resource) in order for this example to work.
Expression:
Patient.extension('http://acme.com/doctor').value.as(Reference)
Example resource that would be indexed by this expression:
{
"resourceType": "Patient",
"extension": [{
"url": "http://acme.com/doctor",
"valueReference": {
"reference": "Practitioner/A"
}
}]
}
Example SearchParameter resource using this expression:
{
"resourceType": "SearchParameter",
"status": "active",
"name": "doctor",
"url": "http://acme.com/doctor-search-parameter",
"code": "doctor",
"base": [ "Patient" ],
"type": "reference",
"expression": "Patient.extension('http://acme.com/doctor').value.as(Reference)"
}
Example search URL using this parameter:
http://localhost:8000/Patient
This example indexes the value on an extension nested inside another extension.
Expression:
Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')
Note that it is not necessary to specify the .value at the end of the FHIRPath expression if the actual value will be a primitive value with a type that is appropriate for the type of the search parameter. For example, if the http://acme.org/bar extension has a value of type string and the SearchParameter is of type string, or if the extension has a value of type Identifier and the value is of type token.
If the value is of type Coding and you wish to specifically index the display value as a string, you could use the following path:
Patient.extension('http://acme.org/foo').extension('http://acme.org/bar').value.as(Coding).display
Example resource that would be indexed by this expression:
{
"resourceType": "Patient",
"extension": [ {
"url": "http://acme.org/foo",
"extension": [ {
"url": "http://acme.org/bar",
"valueString": "HELLO"
} ]
} ],
"name": [ {
"family": "P2"
} ]
}
Example SearchParameter resource using this expression:
{
"resourceType": "SearchParameter",
"title": "Foo",
"status": "active",
"code": "foo",
"base": [ "Patient" ],
"type": "string",
"expression": "Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')",
"xpathUsage": "normal"
}
Example search URL using this parameter:
http://localhost:8000/Patient
The following example indexes on a field that is found within a contained resource inside the resource that is being indexed.
Expression:
Observation.specimen.resolve().receivedTime
Example resource that would be indexed by this expression:
{
"resourceType": "Observation",
"id": "O1",
"contained": [
{
"resourceType": "Specimen",
"id": "FOO",
"receivedTime": "2011-01-01"
}
],
"status": "final",
"specimen": {
"reference": "#FOO"
}
}
Example SearchParameter resource using this expression:
{
"resourceType": "SearchParameter",
"status": "active",
"name": "specimen-received",
"url": "http://acme.com/specimen-received-search-parameter",
"code": "specimen-received",
"base": [ "Observation" ],
"type": "date",
"expression": "Observation.specimen.resolve().receivedTime"
}
Example search URL using this parameter:
http://localhost:8000/Observation
When storing Bundles directly (i.e. by POST-ing them to the /Bundle endpoint as opposed to processing them as FHIR transactions), this path can be used to index on a value within an individual resource found within the Bundle.
Expression:
Bundle.entry.resource.as(MessageHeader).id
Example resource that would be indexed by this expression:
{
"resourceType": "Bundle",
"type": "message",
"entry": [
{
"resource": {
"resourceType": "MessageHeader",
"id": "123"
}
}
]
}
Example SearchParameter resource using this expression:
{
"resourceType": "SearchParameter",
"status": "active",
"name": "message-header-id",
"url": "http://acme.com/message-header-id-search-parameter",
"code": "message-header-id",
"base": [ "Bundle" ],
"type": "token",
"expression": "Bundle.entry.resource.as(MessageHeader).id"
}
Example search URL using this parameter:
http://localhost:8000/Bundle
This example shows a FHIR Document (a bundle with a Bundle.type of document
where the first entry contains a Composition resource) with a custom search parameter indexing a field within the Composition. This example allows clients to search for documents with a given encounter reference.
Expression:
Bundle.entry[0].resource.as(Composition).encounter
Example resource that would be indexed by this expression:
{
"resourceType": "Bundle",
"type": "document",
"entry": [
{
"resource": {
"resourceType": "Composition",
"encounter": {
"reference": "Encounter/2"
}
}
}
]
}
Example SearchParameter resource using this expression:
{
"resourceType": "SearchParameter",
"status": "active",
"name": "document-encounter",
"url": "http://acme.com/document-encounter-search-parameter",
"code": "document-encounter",
"base": [ "Bundle" ],
"type": "reference",
"expression": "Bundle.entry[0].resource.as(Composition).encounter"
}
Example search URL using this parameter:
http://localhost:8000/Bundle
This example indexes multiple paths, meaning it can be used to provide one search parameter that will look for a value in multiple places within a resource.
Expression:
DiagnosticReport.performer | DiagnosticReport.resultsInterpreter
Example resource that would be indexed by this expression:
{
"resourceType": "DiagnosticReport",
"resultsInterpreter": {
"reference": "Practitioner/A"
}
}
Example SearchParameter resource using this expression:
{
"resourceType": "SearchParameter",
"status": "active",
"name": "performer-or-interpreter",
"url": "http://acme.com/performer-or-interpreter-search-parameter",
"code": "performer-or-interpreter",
"base": [ "DiagnosticReport" ],
"type": "reference",
"expression": "DiagnosticReport.performer | DiagnosticReport.resultsInterpreter"
}
Example search URL using this parameter:
http://localhost:8000/DiagnosticReport