Search code examples
jsonapache-nifitransformationjolt

if/else based conversion of data by jolt


I have two following JSON input and I want to convert it into expected output by Jolt

input

{
  "data": [
    {
      "id": "000709000051EEC4_water",
      "type": "watermeter",
      "TimeInstant": "2022-07-28T03:26:56.486Z",
      "address": "xyz",
      "alert_array": {
        "alerts": [
          {
            "alertId": "alt001",
            "severity": "High",
            "alert_type": "Alert",
            "subcategory": "Battery Alert",
            "description": "Low Battery Alert",
            "alertSource": "Battery",
            "data": {
              "parameter": [
                {
                  "key": "battery_percentage",
                  "value": "10",
                  "type": "Integer",
                  "Unit": "%"
                }
              ]
            }
          },
          {
            "alertId": "alt002",
            "severity": "High",
            "alert_type": "Alert",
            "subcategory": "leak",
            "description": "Leakage Alert",
            "alertSource": "pump",
            "data": {
              "parameter": ""
            }
          },
          {
            "alertId": "alt003",
            "severity": "High",
            "alert_type": "Alert",
            "subcategory": "Permanent Error",
            "description": "Permanent Error Alert",
            "alertSource": "pipe",
            "data": ""
          }
        ]
      },
      "alert_count": "3",
      "category": "KWA",
      "dateIssued": "1650957499000",
      "deviceId": "000709000051EEC4",
      "location": "8.4842527, 76.948115",
      "source": " Smart Water Meter - 15 mm",
      "tenantId": "master",
      "transactionId": "t45367598573267"
    }
  ]
}

Expected output

{
  "alertCount": "3",
  "tenantId": "master",
  "transactionId": "t45367598573267",
  "timestamp": "1650957499000",
  "subSystemName": "KWA",
  "location": "xyz",
  "alertArray": [
    {
      "deviceCategory": " Smart Water Meter - 15 mm",
      "deviceId": "000709000051EEC4",
      "alertCategoryName": "Battery Alert",
      "priority": "High",
      "properties": [
        {
          "key": "battery_percentage",
          "value": "10",
          "type": "Integer",
          "Unit": "%"
        }
      ],
      "alertDesc": "Low Battery Alert",
      "alertType": "Alert"
    },
    {
      "deviceCategory": " Smart Water Meter - 15 mm",
      "deviceId": "000709000051EEC4",
      "alertCategoryName": "leak",
      "priority": "High",
      "properties": [],
      "alertDesc": "Leakage Alert",
      "alertType": "Alert"
    },
    {
      "deviceCategory": " Smart Water Meter - 15 mm",
      "deviceId": "000709000051EEC4",
      "alertCategoryName": "Permanent Error",
      "priority": "High",
      "alertDesc": "Permanent Error Alert",
      "alertType": "Alert",
      "properties": []
    }
  ],
  "latitude": "8.4842527",
  "longitude": "76.948115"
}

My output

{
  "alertCount": "3",
  "tenantId": "master",
  "transactionId": "t45367598573267",
  "timestamp": "1650957499000",
  "subSystemName": "KWA",
  "location": "xyz",
  "alertArray": [
    {
      "deviceCategory": " Smart Water Meter - 15 mm",
      "deviceId": "000709000051EEC4",
      "alertCategoryName": "Battery Alert",
      "priority": "High",
      "properties": [
        {
          "key": "battery_percentage",
          "value": "10",
          "type": "Integer",
          "Unit": "%"
        }
      ],
      "alertDesc": "Low Battery Alert",
      "alertType": "Alert"
    },
    {
      "deviceCategory": " Smart Water Meter - 15 mm",
      "deviceId": "000709000051EEC4",
      "alertCategoryName": "leak",
      "priority": "High",
      "properties": "",
      "alertDesc": "Leakage Alert",
      "alertType": "Alert"
    },
    {
      "deviceCategory": " Smart Water Meter - 15 mm",
      "deviceId": "000709000051EEC4",
      "alertCategoryName": "Permanent Error",
      "priority": "High",
      "alertDesc": "Permanent Error Alert",
      "alertType": "Alert"
    }
  ],
  "latitude": "8.4842527",
  "longitude": "76.948115"
}

my spec for transformation

[
  {
    "operation": "shift",
    "spec": {
      "data": {
        "*": {
          "alert_count": "alertCount",
          "tenantId": "tenantId",
          "transactionId": "transactionId",
          "dateIssued": "timestamp",
          "category": "subSystemName",
          "address": "location",
          "location": "newLocation",
          "alert_array": {
            "*": {
              "*": {
                "@(3,source)": "alertArray[&1].deviceCategory",
                "subcategory": "alertArray[&1].alertCategoryName",
                "severity": "alertArray[&1].priority",
                "data": {
                  "parameter": "alertArray[&2].properties"
                },
                "description": "alertArray[&1].alertDesc",
                "alert_type": "alertArray[&1].alertType",
                "@(3,deviceId)": "alertArray[&1].deviceId"
              }
            }
          }
        }
      }
    }
  },
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "newLocation": "=split(',', @(1,&))",
      "latitude": "@(1,newLocation[0])",
      "longitude": "@(1,newLocation[1])"
    }
  },
  {
    "operation": "remove",
    "spec": {
      "newLocation": ""
    }
  },
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "latitude": "=trim",
      "longitude": "=trim"
    }
  }
]

alerts of alert_array one data key that contains three following cases

1- The data contains parameter key and parameter has some information for spec which's working fine

2- The data contains parameter key and parameter is blank string. This spec gives properties as "" but it should give properties as []

3- The data is only a blank string by this result which should give properties as [] , but getting nothing


Solution

  • Just need to add a default transformation spec to the current one such as

    [
      {
        "operation": "shift",
        "spec": {
          "data": {
            "parameter": "properties"
          }
        }
      },
      {
        "operation": "default",
        "spec": {
          "properties": []
        }
      }
    ]
    

    Edit : An alternative method without using default transformation(as mentioned to be desired within the comment) might be

    [
      {
        "operation": "shift",
        "spec": {
          "data": {
            "# ": "properties",
            "parameter": "properties"
          }
        }
      },
      {
        "operation": "modify-overwrite-beta",
        "spec": {
          "*": "=lastElement(@(1,properties))"
        }
      },
      {
        "operation": "modify-overwrite-beta",
        "spec": {
          "*": ["=toInteger", []]
        }
      }
    ]
    

    Edit (based on your lastly edited needs) : You just can convert the last transformation spec to this one :

    {
      "operation": "modify-overwrite-beta",
      "spec": {
        "latitude": "=trim",
        "longitude": "=trim",
        "alertArray": {
          "*": {
            "properties": ["=toInteger", []]
          }
        }
      }
    }
    

    where a string such as "" (or any like "aBc123") will yield a [] as inconvertible to an integer, but an array of objects kept as it is through use of a toInteger conversion