Skip to content

Support {{ thing-json:<json-path> }} placeholder in /migrateDefinition migrationPayload #2319

@thjaeckle

Description

@thjaeckle

Description

Motivation / Use Case

When migrating a Thing to a new definition using the POST /things/{thingId}/migrateDefinition endpoint, the migrationPayload currently only accepts static (literal) values. This makes it impossible to dynamically copy or transform existing data from the Thing during migration.

Consider a scenario where a Thing's definition evolves and a field is renamed or moved:

  • Old definition: Temperature stored at features/sensor/properties/temp
  • New definition: Temperature stored at features/sensor/properties/status/currentTemperature

Currently, the migration must either:

  1. Provide a hardcoded default value (losing the existing data), or
  2. Require a separate API call to read the Thing first, extract the value, then include it in the migration payload

Supporting the {{ thing-json:<json-path> }} placeholder in the migrationPayload would allow users to reference and copy data from the existing Thing in a single migration request.

Proposed Solution

Enable placeholder resolution (specifically thing-json) in the migrationPayload of the MigrateThingDefinition command before merging it with the existing Thing.

The thing-json placeholder already exists in Ditto (used in Connections for outbound message transformation) and allows extracting arbitrary values from a Thing's JSON representation using JsonPointer notation.


Example

Existing Thing (before migration):

{
  "thingId": "org.eclipse.ditto:my-device",
  "definition": "https://models.example.com/sensor-v1.0.0.tm.jsonld",
  "attributes": {
    "manufacturer": "ACME Corp",
    "location": "Building A, Floor 3"
  },
  "features": {
    "sensor": {
      "properties": {
        "temp": 23.5,
        "humidity": 65
      }
    }
  }
}

Migration Request with placeholder support:

POST /api/2/things/org.eclipse.ditto:my-device/migrateDefinition
{
  "thingDefinitionUrl": "https://models.example.com/sensor-v2.0.0.tm.jsonld",
  "migrationPayload": {
    "features": {
      "sensor": {
        "properties": {
          "status": {
            "currentTemperature": "{{ thing-json:features/sensor/properties/temp }}",
            "currentHumidity": "{{ thing-json:features/sensor/properties/humidity }}",
            "lastKnownLocation": "{{ thing-json:attributes/location }}"
          }
        }
      }
    }
  }
}

Resulting Thing (after migration):

{
  "thingId": "org.eclipse.ditto:my-device",
  "definition": "https://models.example.com/sensor-v2.0.0.tm.jsonld",
  "attributes": {
    "manufacturer": "ACME Corp",
    "location": "Building A, Floor 3"
  },
  "features": {
    "sensor": {
      "properties": {
        "temp": 23.5,
        "humidity": 65,
        "status": {
          "currentTemperature": 23.5,
          "currentHumidity": 65,
          "lastKnownLocation": "Building A, Floor 3"
        }
      }
    }
  }
}

Additional Use Cases

  1. Field Renaming: Copy value from old field name to new field name during schema evolution
  2. Data Restructuring: Move nested data to a different location in the Thing hierarchy
  3. Field Consolidation: Combine multiple existing values into a new structure
  4. Conditional Migration: Combined with patchConditions, copy data only when certain conditions are met

Implementation Considerations

  • The thing-json placeholder infrastructure already exists in ImmutableThingJsonPlaceholder (edge-service module)
  • Resolution should happen against the current state of the Thing before any migration changes are applied
  • Type coercion: The resolved value should preserve its original JSON type (number, boolean, string, object, array) rather than converting everything to strings
  • Non-existent paths: When a referenced path doesn't exist, the placeholder should either:
    • Resolve to null / be omitted from the result, or
    • Fail the migration with a clear error message
  • Pipeline functions: Consider supporting the existing pipeline functions (e.g., {{ thing-json:attributes/name | fn:upper() }})

Acceptance Criteria

  • The migrationPayload in MigrateThingDefinition supports {{ thing-json:<json-path> }} placeholders
  • Placeholders are resolved against the Thing's state before any migration changes
  • Resolved values preserve their original JSON type (not converted to string)
  • Missing paths are handled gracefully (either with null/omission or clear error)
  • Dry-run mode (?dry-run=true) shows the resolved payload in the response
  • Documentation updated to describe placeholder support in migration payload
  • Unit tests cover: valid paths, missing paths, nested objects, arrays, type preservation

Related

  • Existing placeholder documentation: Basic Placeholders
  • ImmutableThingJsonPlaceholder implementation in edge/service
  • MigrateThingDefinitionStrategy in things/service

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status

    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions