Modifier Stacking: :not, :in, :missing Without Foot-Guns

Editorial illustration in vaporwave-pastel style depicting three FHIR search modifier cases — :not, :in, and :missing — as annotated panels

FHIR search modifiers turn a plain parameter into a set-operation query. :not inverts, :in filters against a value set, :missing finds resources where the element is absent. Each is useful; each has edge cases; server support is uneven. The site's FHIR search query auditor flags unsupported modifiers before they reach the server. For the wider FHIR framing, additional FHIR product trade-offs has more.

The Three That Actually Get Used

  • :not — returns resources that do NOT match the value
  • :in — returns resources whose coded value is in the referenced ValueSet
  • :missing=true — returns resources where the element is absent
  • :missing=false — returns resources where the element is present

Others exist (:exact, :contains, :above, :below, :identifier, :type), but the top three cover most of the interesting audit territory.

`:not` And the Absence Trap

?code:not=1234-5 returns resources where code is present and not equal to 1234-5. It does not return resources where code is absent. Callers who expect "everything except 1234-5" get a subset that excludes resources with no code at all.

To get "everything not 1234-5 OR missing code," combine :not with :missing=true. For the mechanic, the FHIR searches that look correct but are wrong frames the whole quiet-wrong category.

`:in` Requires the Server To Support Terminology

?code:in=http://example.com/ValueSet/vitals expects the server to expand the ValueSet and match against its members. Servers with weak terminology support handle this poorly — some fall back to string equality, some return errors, some silently ignore the modifier and return all resources.

Test :in explicitly per server before shipping a query that depends on it. When it works, it is the cleanest way to say "one of a set of codes". When it does not, callers get quiet-wrong results.

`:missing=true` And Element Semantics

?date:missing=true returns resources with no date element. Straightforward. Except that some elements are computed at server side and always populated — for those, :missing=true always returns empty. Others are only populated on specific resource types where the profile requires them; on others the same parameter name means something different.

:missing=false is the inverse. It returns resources with a non-null value. Combined with an equality search on the same parameter, ?code=1234-5&code:missing=false is redundant — the equality search already excludes missing values.

Combining Modifiers

Modifiers do not stack on the same parameter. ?code:not:in= is not valid syntax. To get "not in ValueSet X," send ?code:in=ValueSet/X and post-filter, or restructure the query.

Different parameters can carry different modifiers freely. ?code=1234-5&subject:missing=false is fine. That composability is what makes multi-modifier queries readable.

For the encoding side of the same query, reserved characters in search values that break silently covers the value-encoding rules.

What the Auditor Does

The auditor at /dev-tools/audit-fhir-query/ recognises the standard modifiers per parameter type and warns on non-standard or duplicated modifiers. For the broader linter rule set, linter rules to catch the ten most common search mistakes enumerates them.

The Short Version

:not excludes present but non-matching values only. :in needs terminology support. :missing distinguishes absent from present. Modifiers do not stack on one parameter. Test per server, audit at author time.

Vaporwave-pastel diagram of three search modifier cases — :not with absence trap, :in expanding against a ValueSet, :missing separating absent from present — drawn as three panels with magenta accents on a soft dusk-purple background

Sources