Chuyển đến nội dung chính

Bài 9: Bundle, Transaction và Batch - Xử lý nhiều Resources

Resource Bundle và các loại (searchset, transaction, batch, document, message, collection, history). Transaction processing rules, atomic operations, conditional references, batch processing, thực hành tạo transaction bundle.

🏗️ Kiến trúc — Bài 9 Bài 9: Bundle, Transaction và Batch - Xử lý nhiều Resources

HL7 FHIR - Chuẩn Dữ liệu Y tế từ Cơ bản đến Nâng cao

Phần 3: FHIR RESTful API và Data Exchange

xdev.asia

Xem bản video

1. Bundle Resource

Bundle là container chứa nhiều Resources. Nó là cách FHIR xử lý nhiều resources trong một request, đóng gói documents, trả về kết quả search.

Bundle Types

TypeMô tảUse case
searchsetKết quả tìm kiếmResponse của GET search
transactionNhóm operations atomicTạo nhiều resources liên quan
batchNhóm operations independentBulk operations, mỗi entry xử lý độc lập
documentFHIR DocumentClinical document (Composition + resources)
messageFHIR MessageMessaging paradigm (MessageHeader + payload)
collectionBộ sưu tậpGom resources không có interaction cụ thể
historyLịch sử thay đổiResponse của _history
subscription-notificationThông báo subscriptionReal-time notifications

2. Transaction Bundle

Transaction Bundle xử lý atomic — tất cả entries thành công hoặc tất cả rollback.

Ví dụ: Tạo Patient + Encounter + Observation cùng lúc

{
  "resourceType": "Bundle",
  "type": "transaction",
  "entry": [
    {
      "fullUrl": "urn:uuid:patient-temp-1",
      "resource": {
        "resourceType": "Patient",
        "name": [
          {
            "family": "Nguyễn",
            "given": ["Văn", "A"],
            "text": "Nguyễn Văn A"
          }
        ],
        "gender": "male",
        "birthDate": "1990-05-15",
        "identifier": [
          {
            "system": "http://hospital.vn/mrn",
            "value": "MRN-2025-001"
          }
        ]
      },
      "request": {
        "method": "POST",
        "url": "Patient",
        "ifNoneExist": "identifier=http://hospital.vn/mrn|MRN-2025-001"
      }
    },
    {
      "fullUrl": "urn:uuid:encounter-temp-1",
      "resource": {
        "resourceType": "Encounter",
        "status": "in-progress",
        "class": [
          {
            "coding": [
              {
                "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
                "code": "AMB"
              }
            ]
          }
        ],
        "subject": {
          "reference": "urn:uuid:patient-temp-1"
        },
        "period": {
          "start": "2025-01-15T08:00:00+07:00"
        }
      },
      "request": {
        "method": "POST",
        "url": "Encounter"
      }
    },
    {
      "fullUrl": "urn:uuid:obs-temp-1",
      "resource": {
        "resourceType": "Observation",
        "status": "final",
        "category": [
          {
            "coding": [
              {
                "system": "http://terminology.hl7.org/CodeSystem/observation-category",
                "code": "vital-signs"
              }
            ]
          }
        ],
        "code": {
          "coding": [
            {
              "system": "http://loinc.org",
              "code": "8310-5",
              "display": "Body temperature"
            }
          ]
        },
        "subject": {
          "reference": "urn:uuid:patient-temp-1"
        },
        "encounter": {
          "reference": "urn:uuid:encounter-temp-1"
        },
        "valueQuantity": {
          "value": 37.2,
          "unit": "°C",
          "system": "http://unitsofmeasure.org",
          "code": "Cel"
        }
      },
      "request": {
        "method": "POST",
        "url": "Observation"
      }
    }
  ]
}

Conditional References trong Transaction

Sử dụng urn:uuid: làm temporary ID để các entries trong cùng transaction reference nhau. Server sẽ thay thế bằng ID thực tế sau khi tạo.

Transaction Response

{
  "resourceType": "Bundle",
  "type": "transaction-response",
  "entry": [
    {
      "response": {
        "status": "201 Created",
        "location": "Patient/patient-001/_history/1",
        "etag": "W/\"1\"",
        "lastModified": "2025-01-15T08:00:00Z"
      }
    },
    {
      "response": {
        "status": "201 Created",
        "location": "Encounter/encounter-001/_history/1",
        "etag": "W/\"1\""
      }
    },
    {
      "response": {
        "status": "201 Created",
        "location": "Observation/obs-001/_history/1",
        "etag": "W/\"1\""
      }
    }
  ]
}

Transaction Processing Rules

  1. Server xử lý theo thứ tự: DELETE → POST → PUT/PATCH → GET (conditional)
  2. Tất cả entries phải thành công → atomic
  3. Nếu bất kỳ entry nào fail → toàn bộ transaction rollback
  4. urn:uuid: references được resolve trước khi xử lý

3. Batch Bundle

Batch xử lý independent — mỗi entry xử lý riêng, một entry fail không ảnh hưởng entries khác.

{
  "resourceType": "Bundle",
  "type": "batch",
  "entry": [
    {
      "request": {
        "method": "GET",
        "url": "Patient/patient-001"
      }
    },
    {
      "request": {
        "method": "GET",
        "url": "Observation?subject=Patient/patient-001&category=vital-signs&_sort=-date&_count=5"
      }
    },
    {
      "request": {
        "method": "GET",
        "url": "Condition?subject=Patient/patient-001&clinical-status=active"
      }
    },
    {
      "request": {
        "method": "GET",
        "url": "MedicationRequest?subject=Patient/patient-001&status=active"
      }
    }
  ]
}

Use case: Lấy tất cả thông tin bệnh nhân trong một API call thay vì 4 calls riêng biệt.

Batch Response

{
  "resourceType": "Bundle",
  "type": "batch-response",
  "entry": [
    {
      "resource": {"resourceType": "Patient", "id": "patient-001", "...": "..."},
      "response": {"status": "200 OK"}
    },
    {
      "resource": {"resourceType": "Bundle", "type": "searchset", "...": "..."},
      "response": {"status": "200 OK"}
    },
    {
      "resource": {"resourceType": "Bundle", "type": "searchset", "...": "..."},
      "response": {"status": "200 OK"}
    },
    {
      "resource": {"resourceType": "OperationOutcome", "...": "..."},
      "response": {"status": "404 Not Found"}
    }
  ]
}

4. So sánh Transaction vs Batch

Đặc tínhTransactionBatch
Atomicity✅ All-or-nothing❌ Independent
Internal references✅ urn:uuid: resolved❌ Không hỗ trợ
Failure handlingToàn bộ rollbackMỗi entry trả status riêng
PerformanceChậm hơn (transaction boundary)Nhanh hơn (parallel possible)
Use caseData liên quan, cần consistencyBatch read, independent writes

5. Mixed Operations trong Transaction

{
  "resourceType": "Bundle",
  "type": "transaction",
  "entry": [
    {
      "request": {
        "method": "PUT",
        "url": "Patient/patient-001"
      },
      "resource": {"resourceType": "Patient", "id": "patient-001", "active": true}
    },
    {
      "request": {
        "method": "DELETE",
        "url": "Observation/obs-old-001"
      }
    },
    {
      "request": {
        "method": "POST",
        "url": "Observation"
      },
      "resource": {"resourceType": "Observation", "status": "final"}
    },
    {
      "request": {
        "method": "GET",
        "url": "Condition?subject=Patient/patient-001",
        "ifNoneMatch": "W/\"5\""
      }
    }
  ]
}

6. Tổng kết

  • Bundle — Container cho nhiều resources, 8 types khác nhau

  • Transaction — Atomic, all-or-nothing, dùng urn:uuid: cho internal references

  • Batch — Independent processing, parallel, mỗi entry trả status riêng

  • Transaction phù hợp cho data integrity, Batch phù hợp cho performance