Gary Greenberg
Gary Greenberg

Reputation: 1154

conditional JSON transformation in JOLT

I need to process response from SOLR service that looks like following:

{
  "data": {
    "distanceUnits": "mi", //it can be "mi", "MI", "miles", "km", "KM", etc.
    "solrResponse": {
      "header": {
        "found": 32,
        "retrieved": 10,
        ... //there can be other things like timestamp
      },
      "results": [
        {
          "matchScore": "08768",
          "indicators" [{...}],
          "location": {
             ... //there are about hundred attributes
            "distance": "2.7649" //distance always in km
            "similarity": "0.342"
        },
        ...
      ]
}

The transformation need to return everything from solrResponse practically intact except two things:

  1. similarity need to be renamed to similarityScore and moved up next to matchScore.
  2. If distanceUnit is specified as miles, distance need to be converted to miles (i.e. divided by 1.609)
  3. distance value is to berounded to 2 digits after decimal point and concatenated with distanceUnit. I have created the following spec:
[
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "data": {
        "unit1": "=toLower(@(1,distanceUnit))",
        "unit2": "=substring(@(1,unit1),0,1)",
        "solrResponse": {
          "results": {
            "": {
              "dist1": "=divideAndRound(2,@(1,distance),0.6215)",
              "distanceMiles": "=concat(@(1,dist1), ' ', @(2,distanceUnit))",
              "dist2": "=divideAndRound(2,@(1,distance),1.0)",
              "distanceKm": "=concat(@(1,dist2), ' ', @(2,distanceUnit))"
            }
          }
        }
      }
    }
  },
  {
    "operation": "shift",
    "spec": {
      "data": {
        "solrResponse": {
          "header": "&1",
          "response": {
            "": {
              "&1.similarity": "similarityScore",
              "unit2": {
                "m": {
                  "distanceMiles": "locations.distance"
                },
                "": {
                  "distanceKm": "locations.distance"
                }
              },
              "": "&1"
            }
          }
        }
      }
    }
  }
]

Unfortunately it does not work. Please help me.

Upvotes: 0

Views: 709

Answers (1)

Barbaros Özhan
Barbaros Özhan

Reputation: 65323

The Jolt doesn't have a function such as multiply or product, but divide and divideAndRound to be used in a modify transformation spec. Then, we'll have a conditional to filer out whether the provided value for distanceUnit attribute exists within the list(mi,m,Mi,MI) or not such as

[
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "*": { // this outer one represents "locations" list(if there's no other outer level list or object, otherwise replace "*" with the key name "locations") 
        "*": { // this one stands for "locations" list's indexes
          "distanceinMiles_": "=divideAndRound(2,@(1,distance),0.6215040397762585)",
          "distanceinMiles": "=concat(@(1,distanceinMiles_),' ',@(1,distanceUnit))",
          "distance_": "=divideAndRound(2,@(1,distance),1)",
          "distance": "=concat(@(1,distance_),' ',@(1,distanceUnit))"
        }
      }
    }
  },
  {
    "operation": "shift",
    "spec": {
      "*": {
        "*": {
          "address": "&2[&1].&",
          "city": "&2[&1].&",
          "state": "&2[&1].&",
          "postalCode": "&2[&1].&",
          "distanceUnit": {
            "mi|m|Mi|MI": { "@(2,distanceinMiles)": "&4[&3].distance" },
            "*": { "@(2,distance)": "&4[&3].distance" }
          }
        }
      }
    }
  }
]

where

  • @(1,distanceXx) in the first spec represents traversing one colon(:) (as a Right-Hand-Side element) in order to reach the original level of the elements @(1,distanceXx), while @(2,distanceXx) stands for traversing { (object opening "curly" brace) twice to reach the same.

  • the attributes at the indexes level of "locations" are combined by using [&1] and [&3] respectively

  • &2 and &4 are substituted respectively to denote the key name "locations"

the demo on the site http://jolt-demo.appspot.com/ :

enter image description here

Edit (response for your last edit): Considering the input

{
  "data": {
    "distanceUnit": "Mi",
    "solrResponse": {
      "header": {
        "found": 32,
        "retrieved": 10
      },
      "results": [
        {
          "matchScore": "08768",
          "location": {
            "distance": "2.7649",
            "similarity": "0.342"
          }
        }
      ]
    }
  }
}

you can use the following specs

[
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "data": {
        "distanceUnit": "=toLower(@(1,&))",
        "solrResponse": {
          "results": {
            "*": {
              "location": {
                "dist1": "=divideAndRound(2,@(1,distance),0.6215)",
                "distanceKm": "=concat(@(1,dist1), ' km')",
                "dist2": "=divideAndRound(2,@(1,distance),1.0)",
                "distanceMiles": "=concat(@(1,dist2), ' km')"
              }
            }
          }
        }
      }
    }
  },
  {
    "operation": "shift",
    "spec": {
      "data": {
        "*": "&1.&",
        "solrResponse": {
          "*": "&2.&1.&",
          "results": {
            "*": {
              "*": "&4.&3.&2[&1].&",
              "location": {
                "@(4,distanceUnit)": {
                  "mi": { "@(2,distanceKm)": "&7.&6.&5[&4].&3.distance" },
                  "km": { "@(2,distanceMiles)": "&7.&6.&5[&4].distance" }
                },
                "similarity": "&5.&4.&3[&2].&Score"
              }
            }
          }
        }
      }
    }
  }, 
  {
    "operation": "sort"
  }
]

the demo is :

enter image description here

Upvotes: 1

Related Questions