bazaarvoice / jolt

JSON to JSON transformation library written in Java.
Apache License 2.0
1.55k stars 330 forks source link

how to add conditions under modify-overwrite-beta #1234

Closed mordfustang00 closed 7 months ago

mordfustang00 commented 7 months ago

Good day. I'm new to JOLT and i would like to ask on how we can add conditions for modify-overwrite-beta spec.

Here is my sample JSON input:

{ "CarStats": { "odo": { "value": 2000, "unit": 3 (given this is miles value) } }

I want to have this output:

{ "CarStats": { "odo": { "value": 3218.688, "unit": 1 (this is km value) } }

The criteria incase if the unit is 3, i will update value to 1, while at the same time it will calculate the value from miles to km otherwise, the value is as is.

Thanks :)

gbouget commented 7 months ago

Hello,

The trick is to use operation shift.

[
  {
    "operation": "shift",
    "spec": {
      "CarStats": {
        "odo": {
          "unit": {
            "3": { // value => mileValue
              "@(2,value)": "CarStats.odo.mileValue",
              "#1": "CarStats.odo.unit"
            },
            "1": { // value => kmValue
              "@(2,value)": "CarStats.odo.kmValue",
              "@1": "CarStats.odo.unit"
            },
            "*": { // do nothing
              "@(2,value)": "CarStats.odo.value",
              "@1": "CarStats.odo.unit"
            }
          }
        }
      }
    }
  },
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "CarStats": {
        "*": {
          "unit": "=toInteger",
          "mileValue": "=divide(@0,0.621371)"
        }
      }
    }
  },
  {
    "operation": "shift",
    "spec": {
      "CarStats": {
        "odo": {
          "*": "&2.&1.&",
          "kmValue|mileValue": "&2.&1.value"
        }
      }
    }
  }
]

image

mordfustang00 commented 7 months ago

thanks @gbouget it works, but i have another question. if my sample json data has data underneath, how i can display it in the output e.g.:

{ "CarStats": { "odo": { "value": 2000, "unit": 3 }, "fuel": { "value": "100%" }, "battery": { "percentage": "70%" } } }

gbouget commented 7 months ago

With wildcard '*' in LHS (left part) and '&' in RHS (right part).

[
  {
    "operation": "shift",
    "spec": {
      "CarStats": {
        "*": "&1.&", // except 'odo', all attributes will be mapped to &1.& (&1 = one level above, i.e. CarStats) (& = current value of *)
        "odo": { // only matches 'odo'
          "unit": {
            "3": { // value => mileValue
              "@(2,value)": "CarStats.odo.mileValue",
              "#1": "CarStats.odo.unit"
            },
            "1": { // value => kmValue
              "@(2,value)": "CarStats.odo.kmValue",
              "@1": "CarStats.odo.unit"
            },
            "*": { // do nothing
              "@(2,value)": "CarStats.odo.value",
              "@1": "CarStats.odo.unit"
            }
          }
        }
      }
    }
  },
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "CarStats": {
        "*": {
          "unit": "=toInteger",
          "mileValue": "=divide(@0,0.621371)"
        }
      }
    }
  },
  {
    "operation": "shift",
    "spec": {
      "CarStats": {
        "*": "&1.&",
        "odo": {
          "*": "&2.&1.&",
          "kmValue|mileValue": "&2.&1.value"
        }
      }
    }
  }
]
mordfustang00 commented 7 months ago

thanks for this. I noticed that the result has much decimal places. How can we limit up to 2 places only?

gbouget commented 7 months ago
"mileValue": "=divideAndRound(2,@0,0.621371)" // round to 2 decimal places
mordfustang00 commented 7 months ago

thanks :)

mordfustang00 commented 7 months ago

@gbouget i have another question. i'm trying on the following input below (im trying for evRange at least, but trying also for totalAvailrange and gasRange)

Input: { "CarStats": { "odo": { "value": 7363.7, "unit": 3 }, "VehicleStats": { "evStats": { "Distance": [ { "type": 1, "FuelRange": { "evRange": { "value": 138, "unit": 3 }, "totalAvailRange": { "value": 138, "unit": 3 }, "gasRange": { "value": 0, "unit": 3 } } } ], "batteryStats": 75 } } } }

but i have this error (i think it has something to do with [ ] spec formatting: Error running the Transform.

JOLT Chainr encountered an exception constructing Transform className:com.bazaarvoice.jolt.Shiftr at index:0.

Invalid spec, RHS should be a String or array of Strings. Value in question : {FuelRange={evRange={unit={3={@(2,value)=CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.evmileValue, #1=CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.unit}, 1={@(2,value)=CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.evkmValue, @1=CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.unit}, *={@(2,value)=CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.value, @1=CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.unit}}}}}

this is the specs:

[ { "operation": "shift", "spec": { "CarStats": { "": "&1.&", // except 'odo', all attributes will be mapped to &1.& (&1 = one level above, i.e. CarStats) (& = current value of ) "odo": { // only matches 'odo' "unit": { "3": { // value => mileValue "@(2,value)": "CarStats.odo.mileValue", "#1": "CarStats.odo.unit" }, "1": { // value => kmValue "@(2,value)": "CarStats.odo.kmValue", "@1": "CarStats.odo.unit" }, "": { // do nothing "@(2,value)": "CarStats.odo.value", "@1": "CarStats.odo.unit" } } }, "VehicleStats": { "evStats": { "Distance": [ { "FuelRange": { "evRange": { "unit": { "3": { // value => mileValue "@(2,value)": "CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.evmileValue", "#1": "CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.unit" }, "1": { // value => kmValue "@(2,value)": "CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.evkmValue", "@1": "CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.unit" }, "": { // do nothing "@(2,value)": "CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.value", "@1": "CarStats.VehicleStats.evStats.Distance.FuelRange.evRange.unit" } } } } } ] } } } } }, { "operation": "modify-overwrite-beta", "spec": { "CarStats": { "": { "unit": "=toInteger", "mileValue": "=divideAndRound(2,@0,0.621371)" } }, "VehicleStats": { "evStats": { "Distance": [ { "FuelRange": { "evRange": { "unit": "=toInteger", "evmileValue": "=divideAndRound(2,@0,0.621371)" } } } ] } } } }, { "operation": "shift", "spec": { "CarStats": { "": "&1.&", "odo": { "": "&2.&1.&", "kmValue|mileValue": "&2.&1.value" }, "VehicleStats": { "evStats": { "Distance": [ { "FuelRange": { "evRange": { "": "&2.&1.&", "evkmValue|evmileValue": "&2.&1.value" } } } ] } } } } } ]

gbouget commented 7 months ago

To iterate an array with jolt, use:

"key": {
  "*": {
// ...
  }
}

instead of:

"key": [
//...
]

Example image

mordfustang00 commented 7 months ago

thanks :)