{
  "id": "redis-write-same-key",
  "title": "Write to the same key from multiple jobs",
  "url": "https://redis.io/docs/latest/integrate/redis-data-integration/data-pipelines/transform-examples/redis-write-same-key/",
  "summary": "",
  "tags": [
    "docs",
    "integrate",
    "rs",
    "rdi"
  ],
  "last_updated": "2026-05-12T09:07:59-04:00",
  "page_type": "content",
  "content_hash": "61ddd86032247e8d0565f220c9900e9a1c16170a276f0f726f5855feb794a627",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Use this pattern when two or more jobs write related source entities, such as\n`customer` and `address`, to the same Redis JSON document.\n\nWhen multiple jobs write to the same Redis key, a delete event from any of the\nsource entities can delete the key from the target. To work around this, use\n[`row_format: full`](https://redis.io/docs/latest/integrate/redis-data-integration/data-pipelines/transform-examples/redis-row-format#full)\nso the job can inspect the\n[`opcode`](https://redis.io/docs/latest/integrate/redis-data-integration/data-pipelines/transform-examples/redis-opcode-example),\nconvert delete events into update events before writing to Redis, and write JSON\ndocuments with `on_update: merge`.\n\n\nUse the same key expression in all jobs that write to the shared Redis key. For\ndelete events, read key values from `before` or `key` because `after` is `null`."
    },
    {
      "id": "customer-job",
      "title": "Customer job",
      "role": "content",
      "text": "[code example]"
    },
    {
      "id": "address-job",
      "title": "Address job",
      "role": "content",
      "text": "For delete events from the `addresses` table, this job sets all fields to `null`\nto instruct RDI to remove them from the target JSON document. This behavior is\navailable in RDI 1.15.0 or later when native JSON merge is enabled and the target\ndatabase uses RedisJSON 2.6.0 or later.\n\n[code example]"
    }
  ],
  "examples": [
    {
      "id": "customer-job-ex0",
      "language": "yaml",
      "code": "# jobs/customer.yaml\nname: customers\n\nsource:\n  table: customers\n\noutput:\n  - uses: redis.write\n    with:\n      data_type: json\n      on_update: merge\n      key:\n        expression: concat(['customer:', id])\n        language: jmespath",
      "section_id": "customer-job"
    },
    {
      "id": "address-job-ex0",
      "language": "yaml",
      "code": "# jobs/addresses.yaml\nname: addresses\n\nsource:\n  table: addresses\n  row_format: full\n\ntransform:\n  - uses: add_field\n    with:\n      fields:\n        # For create/update records, we take the new values as is.\n        # If the record is a deletion, we set all fields to null.\n        - field: after\n          expression: |\n            (opcode != 'd' && after) \n              || \n            from_entries(to_entries(before)[].{key: key, value: `null`})\n          language: jmespath\n\n        # Treat deletes as updates so that we can use the same output configuration\n        - field: opcode\n          expression: opcode == 'd' && 'u' || opcode\n          language: jmespath\n\n  # If you have overlapping field names (for example, FK and PK have the same name, or both tables have\n  # a field called \"id\"), you may want to remove the field from the after object to prevent it\n  # from overwriting the PK.\n  - uses: remove_field\n    with:\n      field: after.id\n\noutput:\n  - uses: redis.write\n    with:\n      data_type: json\n      on_update: merge\n      key:\n        expression: concat(['customer:', after.customer_id || before.customer_id])\n        language: jmespath",
      "section_id": "address-job"
    }
  ]
}
