Skip to content
Rob Scanlon edited this page Apr 24, 2020 · 25 revisions

Search Using the Models

Associate the client with the model:

FHIR::Model.client = client

The FHIR models can now be used to directly interact with a FHIR server.

For example, you can use FHIR::Patient or FHIR::Encounter or any FHIR resource class to directly search using the search method:

# replace FHIR::Model with an actual resource class such as FHIR::Patient or FHIR::MedicationRequest
FHIR::Model.search(parameters)

The FHIR::Model.search method takes in a hash of search parameters (strings as keys, and strings or numbers as values), and on a successful query returns a FHIR::Bundle instance. On error, the search method raises Exceptions that must be handled.

# search patients
bundle = FHIR::Patient.search(given: 'John', family: 'Doe')
# On success, bundle is a FHIR::Bundle, otherwise an exception is thrown
bundle.each do |resource|
  puts resource.name[0].text
end

If the search is successful, you can use the FHIR::Bundle#each instance method to iterate over the results (even if they are paginated). See automatically paginating search results or manually paginating search results for more information.

You can also search using dates, date times, references, and any other legal search parameters. For example, to search with dates:

# search encounters by date, greater (or after) April 1st 2020
# GET [base]/Encounter?date=gt2020-04-01
bundle = FHIR::Encounter.search(date: 'gt2020-04-01')

See searching by date and time to see the list of modifiers (e.g. gt is greater than) and other examples.

The remainder of the examples below can be used with FHIR::Model.search by using the appropriate parameters shown in each example.

Search Using the Client

There are several search methods built into the client. The most simple example is the "search" involving no parameters.

client.read_feed(klass, format = nil)

In this case klass is the class representing the FHIR resource type to search, e.g. FHIR::Patient or FHIR::Observation, and format is one of four options:

  • FHIR::Formats::ResourceFormat::RESOURCE_XML
  • FHIR::Formats::ResourceFormat::RESOURCE_JSON
  • FHIR::Formats::ResourceFormat::RESOURCE_XML_DSTU2
  • FHIR::Formats::ResourceFormat::RESOURCE_JSON_DSTU2

Examples:

# using the current default format
reply = client.read_feed(FHIR::Patient)
bundle = reply.resource

# overriding the default format to use XML
reply = client.read_feed(FHIR::Observation, FHIR::Formats::ResourceFormat::RESOURCE_XML)
# print the raw XML of the Bundle
puts reply.body
# use the search result bundle (inflated from the raw XML)
bundle = reply.resource

Automatically Paginating Search Results

Assuming read permissions exist on the resource type, a search result will be returned as a FHIR::Bundle instance and the resulting entries can be iterated over using the FHIR::Bundle#each instance method.

reply = client.read_feed(FHIR::Patient) # fetch Bundle of Patients
bundle = reply.resource
bundle.each do |resource|
  puts resource.name[0].text
end
puts reply.code # HTTP 200 (or whatever was returned)
puts reply.body # Raw XML or JSON

Assuming read permissions exist on the resource type, a search result will be returned as a FHIR::Bundle instance which may be paginated. The FHIR::Bundle#each instance method, illustrated above, not only iterates through the FHIR::Bundle#entry array, but it will also fetch the next page of results assuming the Bundle contains a "next" link.

Manually Paginating Search Results

As explained above, using the FHIR::Bundle#each instance method will iterate and paginate results, but if you want to paginate manually, you can do so using the FHIR::Bundle#next_bundle instance method or the FHIR::Client#next_page instance method.

# next_bundle example
reply = client.read_feed(FHIR::Patient) # fetch Bundle of Patients
bundle = reply.resource
another_bundle = bundle.next_bundle

# next_page example
reply = client.read_feed(FHIR::Patient) # fetch Bundle of Patients
bundle = reply.resource
another_reply = client.next_page(reply)

# next_page in a different direction (FOWARD, BACKWARD, FIRST, or LAST)
reply = client.read_feed(FHIR::Patient) # fetch Bundle of Patients
bundle = reply.resource
another_reply = client.next_page(reply, FHIR::Sections::Feed::BACKWARD)

Searching within a single Resource Type

The default search method has the following signature:

def search(klass, options = {}, format = @default_format)
  • klass - the FHIR resource class to search, e.g. FHIR::Patient.
  • options - a Hash of search options described below.
options = {
  :resource => klass,
  :format => format,
  :id => 123, # only use if you are searching by compartment
  :search => {
    :flag => false, # :flag is optional. Search by POST when true, otherwise GET.
    :compartment => 'CompartmentName', # optional searching by compartment
    :parameters => {
      # list of key/value pairs go here
    }
  }
}

Search By Parameter

The name parameter in the following example can be substituted for any combination of parameters as described in http://hl7.org/fhir/R4/search.html including dates, numbers, chaining, and so forth.

# GET [base]/Patient?name=Peter
reply = client.search(FHIR::Patient, search: { parameters: { name: 'Peter' } })
bundle = reply.resource
patient = bundle.entry.first.resource
Search by Date/Time

FHIR date/dateTime searches are documented at http://hl7.org/fhir/R4/search.html#date.

You may need to use the following notation in your search parameters:

  • eq - equal
  • ne - not equal
  • gt - greater than
  • lt - less than
  • ge - greater or equal
  • le - less or equal
  • sa - starts after
  • eb - ends before
  • ap - approximately
# DATE /Encounter?date=gt2020-04-01
client.search(FHIR::Encounter, search: { parameters: { date: 'gt2020-04-01' } })

# DATE using Time
t = Time.now
client.search(FHIR::Encounter, search: { parameters: { date: "eq#{t.to_date.to_s}" } })

# DATETIME /Encounter?date=gt2020-04-01T10:00
client.search(FHIR::Encounter, search: { parameters: { date: 'gt2020-04-01T10:00' } })

# DATETIME using Time
t = Time.now
client.search(FHIR::Encounter, search: { parameters: { date: "gt#{t.iso8601}" } })

# DATE BETWEEN START AND STOP
start = '2020-04-01'
stop = '2020-05-01'
client.search(FHIR::Encounter, search: { parameters: { date: ["gt#{start}", "lt#{stop}"] }})
Search by Reference
# Get an Encounter
reply = client.search(FHIR::Encounter)
bundle = reply.resource
encounter = bundle.entry.first.resource

# Get all Encounters for this subject
client.search(FHIR::Encounter, search: { parameters: { subject: encounter.subject.reference } })

# Get all Observations for a specific encounter
client.search(FHIR::Observation, search: { parameters: { encounter: "Encounter/#{encounter.id}" } })
Searching with AND, OR, and Composite Values

Composite value searching is described in http://hl7.org/fhir/R4/search.html#combining

# AND: /Patient?language=FR&language=NL
client.search(FHIR::Patient, search: { parameters: { language: [ 'FR', 'NL' ] } } )

# OR: /Patient?language=FR,NL
client.search(FHIR::Patient, search: { parameters: { language: 'FR,NL' } })

# COMPOSITE: /Group?characteristic-value=gender$mixed
client.search(FHIR::Group, search: { parameters: { 'characteristic-value': 'gender$mixed' } })

Search within Compartment

# GET [base]/Patient/123/Condition?code:in=http://hspc.org/ValueSet/acute-concerns
reply = client.search(FHIR::Patient, { id: 123,
                      search: {
                        compartment: 'Condition',
                        parameters: { 'code:in': 'http://hspc.org/ValueSet/acute-concerns' }
                      }})
bundle = reply.resource

Search using URL Encoded POST

# POST [base]/Patient/_search?name=Peter
reply = client.search(FHIR::Patient, search: { flag: true, parameters: { name: 'Peter' } })
bundle = reply.resource
patient = bundle.entry.first.resource

Searching Across Resource Types

FHIR allows you to search on a server across multiple, or all, resource types. See http://hl7.org/fhir/R4/search.html#_type.

In order to execute one of these searches, you need to use the client.search_all method.

def search_all(options = {}, format = @default_format)

Example:

# From the spec:
# GET [base]/?_type=Observation,Condition&other params...
results = client.search_all(search: { parameters: { '_type': 'Observation,Condition' } }