Rolf
Rolf

Reputation: 381

How to transform a JSON array to a JSON map: one specific array element attribute value becomes the key of each map

I would like to transform the JSON of the Node.js pm2 process listing (pm2 jlist > pm2-jlist.json) in order to feed it in a slightly different format into collectd (telemetry).

Input JSON:

[
    {
        "pid": 1419,
        "name": "myapp",
        "pm_id": 0,
        "monit": {
            "memory": 13795328,
            "cpu": 0
        }
    },
    {
        "pid": 1425,
        "name": "calendar-viewer",
        "pm_id": 1,
        "monit": {
            "memory": 22761472,
            "cpu": 0
        }
    }
]

Expected Output:

{
    "myapp": {
        "cpu": 0,
        "memory": 14548992,
        "pid": 1419
    },
    "calendar-viewer": {
        "cpu": 0,
        "memory": 16957440,
        "pid": 1425
    }
}

So I want to convert each array element of the Input JSON array to a JSON map element as follows:

  1. The attribute value with the key "name" gets promoted to the key of that map element.

  2. The attributes under the "monit" subtree are consolidated under the key of that map (this part works already).

I cannot get the desired output if the array contains more than one element.

Try#1: this is almost correct but the output contains 2 json objects (invalid syntax) instead of 1 json object...

cat pm2-jlist.json | jq '.[] | {(.name): {pid: .pid,cpu: .monit.cpu, memory: .monit.memory}}'

{
  "myapp": {
    "pid": 1419,
    "cpu": 0,
    "memory": 14548992
  }
}
{
  "calendar-viewer": {
    "pid": 1425,
    "cpu": 0,
    "memory": 16957440
  }
}

Try#2: I can filter out just 1 json object but I want all items in 1 json object...

cat pm2-jlist.json | jq '.[] | select(.name == "calendar-viewer")| {(.name): {pid: .pid, cpu: .monit.cpu, memory: .monit.memory}}'

{
  "calendar-viewer": {
    "pid": 1425,
    "cpu": 0,
    "memory": 16957440
  }
}

Thanks for your time.

Upvotes: 2

Views: 610

Answers (2)

peak
peak

Reputation: 116640

With your input, the filter:

map( { (.name): (.monit + {pid} ) } ) | add

produces:

{
  "myapp": {
    "memory": 13795328,
    "cpu": 0,
    "pid": 1419
  },
  "calendar-viewer": {
    "memory": 22761472,
    "cpu": 0,
    "pid": 1425
  }
}

Upvotes: 2

JonSG
JonSG

Reputation: 13067

I'm not a jq expert, but conceptually what you are after is reduce.

Here is my best guess given how I expect things to work...

reduce .[] as $item ({}; .[$item.name] = {"cpu" : $item.monit.cpu, "memory" : $item.monit.memory, "pid" : $item.pid})

For what it is worth, jqplay.org produces the following output for your input and that above filter:

{
  "myapp": {
    "cpu": 0,
    "memory": 13795328,
    "pid": 1419
  },
  "calendar-viewer": {
    "cpu": 0,
    "memory": 22761472,
    "pid": 1425
  }
}

Upvotes: 1

Related Questions