4

I'm looking to change the data structure of a 3rd party API using JMESPath and haven't been able to figure out how to take a single object of key-value pairs and restructure this to an array of objects, each containing key-value pairs.

I've gone through all of the JMESPath docs and examples without finding the specific data structure I've been working with. I've tried using the keys(@) and values(@) built-in functions to grab the key and values of these pairs, but haven't been able to join them together into a single array.

Here is my original JSON data

{
"time": 32,
    "terms": {
        "192.168.10.121": 84,
        "154.223.10.121": 12,
        "112.149.10.121": 6
    }
}

I'm trying to convert the above JSON data to the following strucutre using JMESPath.

{
"data": [
    { "ip_address": "192.168.10.121", "count": 84 },
    { "ip_address": "154.223.10.121", "count": 12 },
    { "ip_address": "112.149.10.121", "count": 6 }
]}

I've been able to create an array of the keys or an array of values, but not able to create the array of objects containing key-value pairs. terms.{ data: keys(@)} terms.{ data: values(@)}

Result when using terms.{ data: keys(@)}

{
"data": [
    "192.168.10.121",
    "154.223.10.121",
    "112.149.10.121"
]}

Result when using terms.{ data: values(@)}

{
"data": [
    84,
    12,
    6
]}

Those two functions seem like the only functions I can use to pull the keys and values from an object containing key-value pairs not originally within an array. From what I can tell, I'm not able to combine both of those functions to output a single array like my example above.

I'm not even sure this is possible using JMESPath. Any expert opinion would be greatly appreciated.

dreftymac
  • 31,404
  • 26
  • 119
  • 182

1 Answers1

1

Context

  • jmespath query language
  • how to re-normalize data from one structure (schema) to another
  • how to effectively iterate and filter on object properties (name-value pairs)

Pitfalls

  • Generally speaking, jmespath is highly flexible in iterating sequentially-indexed arrays, but much less flexible in iterating over object properties
  • Most transformations with jmespath become extremely cumbersome when the goal is to iterate over object properties
  • Usually you can produce any arbitrary output in jmespath if you are willing to "manually construct" the output by hand ... this is usually the trade-off when dealing with iterating over object properties (aka name-value pairs)

Example

Given the following original dataset ...

{"time": 32,
    "terms": {
        "192.168.10.121": 84,
        "154.223.10.121": 12,
        "112.149.10.121": 6
    }
}

... the following jmespath query ...

{"data": [
  { "ip_address": @.terms|keys(@)[0], "count": @.terms|values(@)[0] }
  ,{ "ip_address": @.terms|keys(@)[1], "count": @.terms|values(@)[1] }
  ,{ "ip_address": @.terms|keys(@)[2], "count": @.terms|values(@)[2] }
]}

... produces the following result

{"data": [
    { "ip_address": "192.168.10.121", "count": 84 },
    { "ip_address": "154.223.10.121", "count": 12 },
    { "ip_address": "112.149.10.121", "count": 6 }
]}
dreftymac
  • 31,404
  • 26
  • 119
  • 182