# Operations for Large Groups/Lists in FHIR ## `$add` operation :::success This instance-level operation merges array entries into an existing ("target") resource, based on values from a supplied ("input") resource, ignoring any values that are already present in the target. ::: :::info #### Example invocation: add two items to a Group This example adds up to 2 new members to the member array of Group 123, based on whether these entity/period combinations already exist. ```json POST /Group/123/$add Content-Type: application/fhir+json If-Match: W/"4" { "resourceType": "Group", "type": "Person", "actual": true, "member": [{ "entity": {"reference": "Patient/123"}, "period": {"start": "2020-07-10"}, }, { "entity": {"reference": "Patient/456"} }] } ``` #### Example invocation: add two items to a List This example adds up to 2 entries to the entry array of List 123, based on whether these item/date combinations already exist. ```json POST /List/123/$add Content-Type: application/fhir+json If-Match: W/"4" { "resourceType": "List", "status": "current", "mode": "working", "entry": [{ "item": {"reference": "Patient/123"}, "date": "2020-01-05" }, { "item": {"reference": "Patient/456"} }] } ``` ::: ### `$add` operation details Instance-level operation, invoked by * `POST /Group/123/$add` to grow `Group.member` * `POST /List/123/$add` to grow `List.entry` * (Other target resource types may be added in future, if use cases arise.) Input Parameter: * `additions`: an input resource matching the type of the target resource. The client SHALL populate all required top-level elements in a way that matches the target resource, to ensure the resource is technically valid. The server SHALL ignore all elements except for the relevant array (e.g., `Group.member` or `List.entry`). Behavior: * The server SHALL extend the target resource array with any entries from the input resource array that do not match an existing entry. See [Matching Algorithm](#Matching-Algorithm). ### Contention Management Clients MAY supply an `If-Match` header with an ETag reflecting the current version of the target resource. Servers SHALL NOT proceed if a supplied ETag does not match the current version of the target resource, following the scheme described at https://hl7.org/fhir/http.html#concurrency. ## `$remove` operation :::success This instance-level operation removes array entries from an existing ("target") resource, based on a supplied ("input") resource, ignoring any values that are already absent in the target. ::: :::info #### Example invocation: remove two items to a Group This example removes elements from the member array of Group 123 if they match the supplied combinations of entity/period. ```json POST /Group/123/$remove Content-Type: application/fhir+json If-Match: W/"4" { "resourceType": "Group", "type": "Person", "actual": true, "member": [{ "entity": {"reference": "Patient/123"}, "period": {"start": "2020-07-10"}, }, { "entity": {"reference": "Patient/456"}, }] } ``` #### Example invocation: add two items to a List This example removes elements from the entry array of List 123 if they match the supplied combinations of item/date. ```json POST /List/123/$remove Content-Type: application/fhir+json If-Match: W/"4" { "resourceType": "List", "status": "current", "mode": "working", "entry": [{ "item": {"reference": "Patient/123"}, }, { "item": {"reference": "Patient/456"}, "date": "2020-01-12" }] } ``` ::: ### `$remove` operation details Instance-level operation, invoked by * `POST /Group/123/$remove` to shrink `Group.member` * `POST /List/123/$remove` to shrink `List.entry` * (Other target resource types may be added in future, if use cases arise.) Input Parameter: * `removals`: an input resource matching the type of the target resource. The client SHALL populate all required top-level elements in a way that matches the target resource, to ensure the resource is technically valid. The server SHALL ignore all elements except for the relevant array (e.g., `Group.member` or `List.entry`). Behavior: * The server SHALL remove any entries in the target resource's array that match an entry in the input resource's array. See [Matching Algorithm](#Matching-Algorithm). ### Contention Management Clients MAY supply an `If-Match` header with an ETag reflecting the current version of the target resource. Servers SHALL NOT proceed if a supplied ETag does not match the current version of the target resource, following the scheme described at https://hl7.org/fhir/http.html#concurrency. ## `$filter` operation :::success This instance-level operation returns the subset of array entries from an existing ("target") resource that match values from a supplied ("input") resource. ::: :::info #### Example invocation: filter a List by Patient This example filters List 123 to return items referencing Patient 456 (on any day) Patient 789 (in July 2022. ```json POST /List/123/$filter Content-Type: application/fhir+json { "resourceType": "List", "status": "current", "mode": "working", "entry": [{ "item": {"reference": "Patient/456"}, }, { "item": {"reference": "Patient/789"}, "date": "2022-07" }] } ``` If this list included two items (with any date) referencing Patient 456, and one item with a date in July 2022 referencing Patient 789, then three subsetted entries would be returned: ```json { "resourceType": "List", "id": "123", "meta": { "tag": [{ "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationValue", "code": "SUBSETTED" }] }, "status": "current", "mode": "working", "title": "Patient waiting list", "entry": [{ "date": "2022-07-01", "flag": {"text": "Registered"}, "item": {"reference": "Patient/456/_history/1"} }, { "date": "2022-07-02T11:00:00Z", "flag": {"text": "Escalated"}, "item": {"reference": "Patient/456/_history/2"} }, { "date": "2022-07-02T12:00:00Z", "flag": {"text": "Escalated"}, "item": {"reference": "Patient/789"} }] } ``` ::: ### `$filter` operation details Instance-level operation, invoked by * `POST /Group/123/$filter` to return a filtered subset of `Group.member` * `POST /List/123/$filter` to return a filtered subset of `List.entry` * (Other target resource types may be added in future, if use cases arise.) Input Parameter: * `probes`: an input resource matching the type of the target resource. The client SHALL populate all required top-level elements in a way that matches the target resource, to ensure the resource is technically valid. The server SHALL ignore all elements except for the relevant array (e.g., `Group.member` or `List.entry`). Behavior: * The server SHALL determine which existing array entries in the target resource "match" each entry in the input resource. See [Matching Algorithm](#Matching-Algorithm). * The server SHALL return a resource that includes all matching array entries * The returned resource SHALL include a `SUBSETTED` Coding in `.meta.tag` --- :::success ### Matching Algorithm Applies to: `$add`, `$remove`, and `$filter`. This algorithm determines whether an entry in the target resource array "matches" an entry in the input resource array. An entry is considered to "match" if: * each supplied element in the input entry is present in the target entry AND * each supplied element has a value in the target entry that is: * identical to the value in the input entry OR * more specific than the value in the input entry * a date is "more specific" if it covers a narrower timespan, e.g. an input value of "2022-07" would match a target value of "2022-07-01" * a reference is "more specific" if it points to a historical version, e.g. an input value of "Patient/123" would match a target value of "Patient/123/_history/456" --- ##### Example 1: a single probe Entry in input resource: ```json { "item": {"reference": "Patient/123"} } ``` Entry in target resource: ```json { "date": "2022-07-01", "item": {"reference": "Patient/123/_history/2"} } ``` Result: this is a **match**, because the target entry contains a matching element for the input entry's elements (`item` and `item.reference`). The presence of an additional `date` element in the target resource does not affect the result. --- ##### Example 2: asymmetry Now consider the same inputs from Example (1), but swap their roles (input / target) as follows. Entry in input resource: ```json { "date": "2022-07-01", "item": {"reference": "Patient/123/_history/2"} } ``` Entry in target resource: ```json { "item": {"reference": "Patient/123"} } ``` Result: this is **not a match**, because the target entry contains no match for the input entry's `date` element, and also no match for the input entry's version-specific `item.reference` element. This example shows that the comparision operation is not symmetric; inputs match more-specific targets, not less-specific targets. :::