Каждое поле внутри FHIR-ресурса называется element — это содержимое «карточки» из fhir-basics. Эта страница — глоссарий устройства одной карточки: какие категории значений бывают, как описывается cardinality, какие DataTypes часто встречаются, какие universal slots есть на каждом ресурсе.

В FHIR-спеке Element — это базовый abstract class от которого наследуется всё (включая BackboneElement, DataType, и каждое поле в каждом ресурсе)1.

1. Три категории элементов

Внутри карточки лежит контент трёх «уровней»:

  1. Primitive types — атомарные значения. string, code, integer, dateTime, uri, boolean, decimal. Не имеют внутренней структуры — одно значение.

    "status": "final"              // code — примитив
    "birthDate": "1980-03-15"      // date — примитив
    "active": true                  // boolean — примитив
  2. DataTypes (complex types) — структуры без identity, существуют только внутри ресурса. Identifier, CodeableConcept, Reference, HumanName, Quantity, Period, Annotation, Address. Не хранятся самостоятельно, не имеют URL.

    "name": {                      // HumanName — DataType
      "family": "Иванов",
      "given": ["Иван", "Сергеевич"]
    }
  3. Resources — структуры с identity (id + URL), хранятся в FHIR-сервере отдельно. Patient, Observation, Condition, Composition. Связи с другими карточками — через DataType Reference, который указывает на URL.

Patient (Resource — имеет id, хранится на сервере)
  ├── name: HumanName (DataType — без id, лежит внутри)
  │     ├── family: "Иванов"          ← primitive (string)
  │     └── given: ["Иван", ...]      ← массив primitive
  ├── birthDate: "1980-03-15"          ← primitive (date)
  └── managingOrganization: Reference  ← DataType ссылка
        └── reference: "Organization/clinic-1"  ← primitive (string-URL)

DDD-параллель: Resource ≈ Entity (имеет identity), DataType ≈ Value Object (без identity, equal-by-value). См. domain-driven-design.

На реальном примере — US Core Lab Observation

US Core Laboratory Result Observation (Serum Total Bilirubin) — иллюстрация трёх категорий элементов

Канонический US Core Lab Result example — Serum Total Bilirubin. Профайл: us-core-observation-lab. Источник Mermaid — attachments/uscore-observation-lab-elements.mmd.

На что смотреть:

  • 🟦 Observation — Resource (id serum-total-bilirubin, хранится на сервере по /Observation/{id}).
  • 🟦 пунктир — другие Resources (Patient/example, Specimen/serum), на которые ссылается Observation через Reference.
  • 🟩 DataTypes (без identity, живут внутри): code, category, interpretation (все три — CodeableConcept); valueQuantity (Quantity — choice type value[x] разрешённый в Quantity); subject / specimen (Reference); referenceRange[0] (BackboneElement — inline struct).
  • 🟨 Primitive поля — каждое атомарное значение отдельной нодой: status: 'final', effectiveDateTime: '2005-07-07' (choice type effective[x] разрешённый в primitive date), value: 8.6 + unit: 'mg/dL' + system + code внутри Quantity, и т.д.
  • 🟥 Universal slot meta с profile[0] — claim of conformance к us-core-observation-lab v7.0.0.

Этот один пример покрывает всю таксономию страницы: три категории, два choice types (effective[x] → primitive, value[x] → DataType), два Reference’а на внешние ресурсы, BackboneElement как третий вид inline-структуры, и universal slot meta.

2. Notation полей — как описывается одно поле в спеке

Когда читаешь FHIR-спеку (hl7.org/fhir/R4/<resource>.html), у каждого поля в таблице показано несколько маркеров:

  • Cardinalitymin..max (0..1, 1..1, 0..*, 1..*)
  • Type — какой DataType / Resource в этом поле (string, CodeableConcept, Reference(Patient), …)
  • Flags — компактные маркеры в отдельной колонке:
    • Σ — element включается в summary view
    • ?!modifier, влияет на интерпретацию ресурса (нельзя игнорировать)
    • I — на поле висят invariants (FHIRPath constraints)
    • S — must-support (в IG); NE — non-empty
  • Binding — для code/Coding/CodeableConcept полей: required / extensible / preferred / example (насколько строго привязан value set)
  • [x] суффикс в имени — поле может быть одного из нескольких типов (choice type)

Ниже разбираем cardinality и choice types подробнее — это самые часто встречающиеся в обсуждениях. Про флаги (особенно ?! modifier) — отдельные секции в fhir-conformance-resources; binding — в fhir-terminology-service.

Cardinality (min..max)

В FHIR-спеке каждое поле сопровождается записью min..max2:

ЗаписьЧто значит
0..1Optional, не более одного. Может отсутствовать или быть одно значение.
1..1Required, ровно одно. Обязано присутствовать.
0..*Optional массив. Может отсутствовать, быть пустым, или содержать любое число элементов.
1..*Массив, обязан содержать хотя бы один элемент.
2..4Массив, от 2 до 4 элементов (редко, обычно встречается в специфичных профилях).
  • min — минимальное число вхождений (0 = optional, 1+ = required)
  • max — максимальное (1 = singular, * = unbounded)

0..* — самый частый кардинальный паттерн для коллекций (Patient.identifier, Observation.component, Bundle.entry). Порядок элементов в массиве стандартом не специфицирован — нельзя полагаться на array[0], надо искать по system / code / discriminator поля. Профилирование через slicing решает эту проблему (см. fhir-profiling).

В FHIR-builder коде кардинальность определяет shape кода: 1..1 поле — всегда обязательный аргумент функции; 0..* — массив с возможно нулевой длиной; 0..1 — optional с if проверкой при сериализации.

Choice types ([x] суффикс)

Когда поле может содержать значение одного из нескольких типов, спека пишет имя[x] с квадратным «x» в суффиксе. В реальном JSON это разворачивается в одно конкретное имя — <имя><Тип> — и только одно значение задаётся одновременно (не оба):

// authorReference вариант:
{ "authorReference": { "reference": "Organization/bloodgpt" }, "time": "...", "text": "..." }
 
// authorString вариант:
{ "authorString": "Dr. Smith", "time": "...", "text": "..." }

Примеры choice types в стандарте:

  • Annotation.author[x]authorReference (Practitioner / Device / Organization / Patient) или authorString (свободная строка)
  • Observation.value[x]valueQuantity / valueCodeableConcept / valueString / valueBoolean / … (≈15 типов)
  • Observation.effective[x]effectiveDateTime / effectivePeriod / effectiveInstant / effectiveTiming
  • Procedure.performed[x]performedDateTime / performedPeriod / performedString (для нечётких дат типа «5 лет назад»)
  • MedicationStatement.medication[x]medicationCodeableConcept (просто код) или medicationReference (на отдельный Medication ресурс)
  • Patient.deceased[x]deceasedBoolean / deceasedDateTime
  • Extension.value[x] — universal для extensions (valueString / valueQuantity / любой data type)

Паттерн «Reference vs String» (богатая ссылка vs простая строка) — частный случай: даёт выбор между референсной структурой (с metadata, versioning, search) и быстрой текстовой строкой. Reference используется когда сущность за полем — самостоятельная (Practitioner с credentials), String — когда хочется short-circuit и сохранять только имя без полной модели.

Failure mode parsing’а — попытаться задать оба варианта (authorReference + authorString в одном объекте). FHIR-валидаторы это ловят как ошибку схемы.

3. Ключевые DataTypes

Здесь — три DataTypes которые нужно понимать чтобы читать любой клинический ресурс: они задействованы в специфичных паттернах работы (matching по system+value, multi-coding, ссылки-vs-identifier-vs-contained). Остальные complex types (Quantity — число с единицей, Period — диапазон дат, HumanName, Address, ContactPoint, Annotation, Timing — расписание, Attachment, Ratio, Range, Money) grok’аются на лету по форме — полный список и поля каждого в hl7.org/fhir/R4/datatypes.html3.

Identifier — бизнес-идентификаторы

Identifier — DataType для бизнес-идентификаторов (MRN — Medical Record Number, SSN — Social Security Number, lab accession number, и т.п.). Структура:

{
  "system": "http://hospital.example.org/mrn",  // namespace (что за идентификатор)
  "value": "P-12345",                            // значение в этом namespace
  "use": "official",                             // usual | official | temp | secondary | old
  "type": { ... },                               // optional CodeableConcept
  "period": { ... }                              // когда действителен
}

Ключевое: system + value это пара. Один и тот же value (например "12345") может значить разные вещи в разных system. Поэтому идентификаторы матчатся парой, не одним value:

patient.identifier.find(i =>
  i.system === "http://hospital.example.org/mrn" && i.value === "P-12345"
)

system обычно — URL (http://hospital.example.org/mrn) или OID URN (urn:oid:2.16.840.1.113883.4.1 для US SSN). Каноничные system URLs для регулируемых идентификаторов фиксируются в IG (US Core / RuCore).

CodeableConcept / Coding / code — три уровня кодирования

FHIR имеет три level’а для «кодов» в зависимости от нужной точности.

code (primitive) — простая строка из закрытого enum, специфичного для данного поля. Используется когда value set маленький, фиксированный, и cross-system маппинг не нужен. Это primitive type, не data type.

"status": "final"           // Observation.status: registered | preliminary | final | ...

Coding (DataType) — структура { system, code, display, version? } — одиночный код из именованной кодовой системы.

{
  "system": "http://loinc.org",
  "code": "2093-3",
  "display": "Cholesterol, Total"
}

CodeableConcept (DataType) — обёртка вокруг массива Coding[] плюс free-text fallback:

{
  "coding": [
    { "system": "http://loinc.org",        "code": "2093-3",    "display": "Cholesterol" },
    { "system": "http://snomed.info/sct",  "code": "77068001",  "display": "Cholesterol" }
  ],
  "text": "общий холестерин"
}

Зачем массив coding: одно и то же понятие можно одновременно закодировать в двух кодовых системах (LOINC + SNOMED) — это упрощает downstream consumer’у который понимает только одну. text — для human-readable fallback’а если все coding’и unfamiliar.

Правило большого пальца:

  • Внутреннее поле статуса/типа с фиксированным enum → code
  • Один код из стандарта (LOINC / SNOMED / RxNorm / ICD-10) → Coding
  • Клинический концепт где может быть multi-coding или text fallback → CodeableConcept

В FHIR-ресурсах подавляющее большинство «code»-полей — CodeableConcept, чтобы дать гибкость и multi-coding.

Reference — ссылка между ресурсами

Reference — DataType указывающий на другой ресурс4. Структура:

{
  "reference": "Patient/123",              // relative URL или absolute
  "type": "Patient",                       // optional подтверждение типа
  "identifier": { ... },                   // optional — reference через identifier вместо URL
  "display": "John Doe"                    // optional human-readable
}

Форматы reference:

  • Relative"Patient/123" (на том же FHIR-сервере)
  • Absolute"https://other-server.example.org/fhir/Patient/123" (внешний)
  • UUID"urn:uuid:b9a3d6a7-..." (только внутри Bundle для transactional resolution до server-assigned ID)
  • Versioned"Patient/123/_history/5" (привязка к конкретной версии)

Identifier-reference (логическая ссылка без URL) — { identifier: { system, value } }. Полезно когда target пока не создан в FHIR-store, но известен его business identifier (MRN, lab accession number). См. llm-fhir-linkback.

Contained resourcesPatient.contained: [Resource] плюс reference: "#localId" для ссылки внутри родительского. Альтернатива для anonymous nested ресурсов без identity.

4. Universal slots на каждом ресурсе

Это не специфичные DataTypes, а mechanisms которые есть на любом Resource или элементе. Их две: meta (на уровне Resource — server/operational metadata) и extension (на любом элементе — custom-поля).

meta — server-side и operational metadata

Каждый Resource имеет meta-блок:

"meta": {
  "versionId": "5",                        // server-assigned version
  "lastUpdated": "2026-05-16T14:00:00Z",   // server timestamp
  "source": "https://bloodgpt.app",        // origin URL
  "profile": [                             // claim conformance к этим профилям
    "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
  ],
  "security": [ Coding ],                  // access control tags
  "tag": [ Coding ]                        // operational tags (custom semantics)
}
  • versionId / lastUpdated — сервер назначает, не клиент
  • profile — claim ресурса о соответствии конкретным профилям (fhir-profiling)
  • security — access control (например confidentiality, redaction)
  • tag — operational metadata. Мы используем для origin tracking (source-chat / source-survey / source-document-import) — см. fhir-meta-tagging и fhir-resource-origin-and-lifecycle.

Extension — механизм custom-полей

Базовый ресурс не покрывает всё, что нужно конкретной экосистеме (custom-поля, специфичные для рынка / vendor / use case). FHIR имеет универсальный механизм extension — добавить custom поле через структуру { url, value[x] }5:

"extension": [
  {
    "url": "http://hospital.example.org/StructureDefinition/admission-channel",
    "valueString": "emergency-room"
  }
]

url — каноническая ссылка на StructureDefinition extension’а (где описано что это за поле, какой тип, etc). value[x] — само значение (типизировано: valueString, valueDateTime, valueCodeableConcept, …).

Extensions могут быть standard (определены в HL7 или в realm-IG) или custom (locally-defined). Применяются на любом уровне — на ресурсе целиком, на элементе, или даже на DataType.

Наша политика — минимизировать extensions. Детали — zero-extensions-fhir. Полная механика profiling и extensions — fhir-profiling. Конкретные URL conventions для собственных extensions — extension-url-conventions.

5. Bundle — контейнер ресурсов

Bundle — особый Resource, который оборачивает группу других ресурсов6. Семантика зависит от Bundle.type:

TypeСмысл
transactionАтомарный batch CRUD — сервер применяет всё или ничего. Resolve внутренних UUID-ссылок.
batchНеатомарный batch CRUD — каждый entry независим, failures одного не блокируют другие.
documentФиксированная структура: первый entry — Composition, дальше — referenced ресурсы. Документ-как-целое. Подпись через Bundle.signature.
collectionBag of resources без специфической семантики — просто группа.
searchsetServer response на search — entries это matching ресурсы + included.
historyServer response на history-операцию — versions ресурса.
messageAsync messaging — первый entry это MessageHeader.

В нашем стеке мы используем в основном transaction (атомарный POST множества ресурсов из одного analysis run — Composition + Observations + AllergyIntolerances + и т.п.) и searchset (server output). См. fhir-bundle для production-deep dive.

Связано

  • fhir-basics — введение в FHIR через метафору карточек и связей между ними
  • fhir-resource-categories-overview — модули FHIR + альтернативный взгляд по скорости изменения
  • fhir-bundle — production-deep dive по Bundle (transaction-семантика, UUID resolution)
  • fhir-conformance-resources — meta-ресурсы которые формально описывают сами elements (StructureDefinition / ValueSet)
  • fhir-profiling — как накладывать constraints на elements через StructureDefinition profiles
  • zero-extensions-fhir — наша политика по extensions — active
  • extension-url-conventions — URL conventions для собственных extensions — draft
  • fhir-meta-tagging — конкретный use case meta.tag (origin tracking)
  • fhir-resource-origin-and-lifecycle — где живёт meta.tag в нашем pipeline
  • domain-driven-design — Resource ≈ Entity, DataType ≈ Value Object параллель

Сноски

  1. HL7 FHIR R4 — Element type (base class), accessed 2026-05-19, https://hl7.org/fhir/R4/element.html.

  2. HL7 FHIR R4 — Cardinality concepts, accessed 2026-05-17, https://www.hl7.org/fhir/conformance-rules.html.

  3. HL7 FHIR R4 — DataTypes overview, accessed 2026-05-17, https://www.hl7.org/fhir/datatypes.html.

  4. HL7 FHIR R4 — References between resources, accessed 2026-05-17, https://www.hl7.org/fhir/references.html.

  5. HL7 FHIR R4 — Extensibility (extension mechanism), accessed 2026-05-19, https://hl7.org/fhir/R4/extensibility.html.

  6. HL7 FHIR R4 — Bundle, accessed 2026-05-17, https://www.hl7.org/fhir/bundle.html.