Search code examples
jsonata

How to use jsonata to return multiple objects, distributing the first key/value, which will always be dateTime, with the remaining keys varying


How can jsonata be used to transform:

{
  "data": [
    {
      "dateTime": "2019-10-19T12:53:54.043Z",
      "Reactor3.Level": 1.51860072870498,
      "Reactor3.Temp": 27.1360543141452
    },
    {
      "dateTime": "2019-10-19T12:55:54.043Z",
      "Reactor3.Press": 88.9,
      "Reactor3.Temp": 24.1418981047159
    }
  ]
}

Into a series of objects containing only two keys of {"dateTime":"2019-10-19T12:53:54.043Z", key[1]:value[1]},{"dateTime":"2019-10-19T12:53:54.043Z",key[2]:value[2]} Such as the following:

{
  "data": [
    {
      "dateTime": "2019-10-19T12:53:54.043Z",
      "Reactor3.Level": 1.51860072870498
    },
    {
      "dateTime": "2019-10-19T12:53:54.043Z",
      "Reactor3.Temp": 27.1360543141452
    },
    {
      "dateTime": "2019-10-19T12:55:54.043Z",
      "Reactor3.Press": 88.9
    },
    {
      "dateTime": "2019-10-19T12:55:54.043Z",
      "Reactor3.Temp": 24.1418981047159
    }
  ]
}

Where the first key will always be dateTime, the other keys will vary, and I'd like to break out all other keys/values by dateTime? Here Reactor3.Level, Reactor3.Temp, Reactor3.Press are just examples that will change.

EDIT: In the following I am adding a more generic version of my problem. I am essentially looking for a JSONata query to transform this input:

{
  "data": [
    {
      "TS": "TS1",
      "V1": 1,
      "V2": 2
    },
    {
      "TS": "TS2",
      "V2": 9,
      "V3": 8,
      "V4": 7
    }
  ]
}

where key "TS" is the first key in every set, and the other keys will vary. And transform it into this output:

{
  "data": [
    {
      "TS": "TS1",
      "V1": 1
    },
    {
      "TS": "TS1",
      "V2": 2
    },
    {
      "TS": "TS2",
      "V2": 9
    },
    {
      "TS": "TS2",
      "V3": 8
    },
    {
      "TS": "TS2",
      "V4": 7
    }
  ]
}

[SOLVED] SteveR solved my problem below, I just want to add a Node-RED "payload" friendly version of the solution here: Link: http://try.jsonata.org/HJCjoHxoS

payload modified JSONata:

payload.$ ~> | $ | { "data": data.(
    $obj := $;
    $key := "dateTime";
    $keys($obj)[$ != $key].{
        $key : $lookup($obj, $key),
        $: $lookup($obj, $)
    }
) } |

Thanks again to @SteveR


Solution

  • Interesting challenge, Jeff -- but if object properties do not have a guaranteed order, it may not be possible to do reliably... is it always the "first" property that needs to be distributed over the rest of them, or can you say for sure that it will always be called TS (using your simplified example)?

    That being said, I did find an expression that seems to work, albeit only within my limited testing:

    data.(
        $obj := $;
        $keys($obj)[[1..100]].(
            $key := $keys($obj)[0];
            {
                $key : $lookup($obj, $key),
                $: $lookup($obj, $)
            }
        )
    )
    

    Essentially, for each of the incoming objects, get its keys -- for each key with index between 1 - 100 (I know, it's an artificial limit), create the new object { key[0]: val[0], key[i]: val[i] }

    You can try to tweak it here if you would like => http://try.jsonata.org/ryh3hqM5H

    If you can say for sure that the first property is called "TS", I would use that named property to simplify the expression, like this:

    data.(
        $obj := $;
        $key := "TS";
        $keys($obj)[$ != $key].{
            $key : $lookup($obj, $key),
            $: $lookup($obj, $)
        }
    )
    

    I'm sure there are better ways to accomplish the same transformation, but I hope this helps...

    Good luck!

    EDIT: I see that I lost the outer object with its data property. You can just wrap it around the expression(s) I listed, or if there are other properties that need to be maintained, use the object transform syntax to only modify that one data property:

    $$ ~> | $ | { "data": data.(
        $obj := $;
        $key := "dateTime";
        $keys($obj)[$ != $key].{
            $key : $lookup($obj, $key),
            $: $lookup($obj, $)
        }
    ) } |