Using a function to add new JSON keys

I’m currently processing a list of systems processed in a vulnerability scan. Each host has a list of tags associated with it. I’ve created a function that will turn the tags into a comma-separated list to be pushed to a reporting database (PostgreSQL), but I can’t figure out how to add a new key to each host entry to store it. The closest I can get is a running list of all tags from all systems in the source data concatenated together. Function code below (with commented out attempt to insert is as a new key for each host):

item.tagList = "";
for(const hostitem of $json["host_list_output"]["response"]["host_list"]["host"])
{
  for(const tagname of hostitem["tags"]["tag"])
  {
    item.tagList += tagname["name"] + ", ";
  }
  if(item.tagList.length > 0)
  {
    item.tagList = item.tagList.slice(0, -2);
  }
  //item.host_list_output.response.host_list.host.tagList = item.tagList;
  //item.tagList = "";
}
return item;

This is a sample of the source data I’m working from (Qualys, for the curious):

{
"host_list_output": {
"response": {
"datetime": "2021-06-17T17:18:02Z",
"host_list": {
"host": [
{
"id": "<masked id>",
"ip": "<masked ip>",
"tracking_method": "IP",
"dns": "<masked FQDN>",
"dns_data": {
"hostname": "<masked hostname>",
"domain": "<masked domain>",
"fqdn": "<masked FQDN>"
},
"tags": {
"tag": [
{
"tag_id": "37724688",
"name": "Not scanned in 90 days"
},
{
"tag_id": "46439938",
"name": "Internet Facing Assets"
},
{
"tag_id": "63812476",
"name": "OS: Linux x.x"
},
{
"tag_id": "78797433",
"name": "Not scanned in 30 days"
},
{
"tag_id": "78797434",
"name": "Not scanned 120 days"
},
{
"tag_id": "78966920",
"name": "OS: Ubuntu xx"
},
{
"tag_id": "78966927",
"name": "OS: Linux 2.x"
}
]
},
"last_vuln_scan_datetime": "2020-03-04T12:40:17Z",
"last_vm_scanned_date": "2020-03-04T12:40:17Z",
"last_vm_scanned_duration": "564"
},

Any ideas on where I’m going wrong?

Given the input that you provided, can you provide an example of a successful output?

Something along these lines:

{
“host_list_output”: {
“response”: {
“datetime”: “2021-06-17T17:18:02Z”,
“host_list”: {
“host”: [
{
“id”: “”,
“ip”: “”,
“tracking_method”: “IP”,
“dns”: “”,
“dns_data”: {
“hostname”: “”,
“domain”: “”,
“fqdn”: “”
},
“tags”: {
“tag”: [
{
“tag_id”: “37724688”,
“name”: “Not scanned in 90 days”
},
{
“tag_id”: “46439938”,
“name”: “Internet Facing Assets”
},
{
“tag_id”: “63812476”,
“name”: “OS: Linux x.x”
},
{
“tag_id”: “78797433”,
“name”: “Not scanned in 30 days”
},
{
“tag_id”: “78797434”,
“name”: “Not scanned 120 days”
},
{
“tag_id”: “78966920”,
“name”: “OS: Ubuntu xx”
},
{
“tag_id”: “78966927”,
“name”: “OS: Linux 2.x”
}
]
},
“last_vuln_scan_datetime”: “2020-03-04T12:40:17Z”,
“last_vm_scanned_date”: “2020-03-04T12:40:17Z”,
“last_vm_scanned_duration”: “564”,
“tagList”: “Not scanned in 90 days, Internet Facing Assets, OS: Linux x.x, Not scanned in 30 days, Not scanned 120 days, OS: Ubuntu xx, OS: Linux 2.x”
},

Note the new tagList key.

The example below should do it.

{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "return [\n  {\n    json: \n    \n    {\n\t\"host_list_output\": {\n\t\t\"response\": {\n\t\t\t\"host_list\": {\n\t\t\t\t\"host\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"id\": \"\",\n\t\t\t\t\t\t\"ip\": \"\",\n\t\t\t\t\t\t\"tracking_method\": \"IP\",\n\t\t\t\t\t\t\"dns\": \"\",\n\t\t\t\t\t\t\"dns_data\": {\n\t\t\t\t\t\t\t\"hostname\": \"\",\n\t\t\t\t\t\t\t\"domain\": \"\",\n\t\t\t\t\t\t\t\"fqdn\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tags\": {\n\t\t\t\t\t\t\t\"tag\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"tag_id\": \"37724688\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Not scanned in 90 days\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"tag_id\": \"46439938\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Internet Facing Assets\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"tag_id\": \"63812476\",\n\t\t\t\t\t\t\t\t\t\"name\": \"OS: Linux x.x\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"tag_id\": \"78797433\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Not scanned in 30 days\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"tag_id\": \"78797434\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Not scanned 120 days\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"tag_id\": \"78966920\",\n\t\t\t\t\t\t\t\t\t\"name\": \"OS: Ubuntu xx\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"tag_id\": \"78966927\",\n\t\t\t\t\t\t\t\t\t\"name\": \"OS: Linux 2.x\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"last_vuln_scan_datetime\": \"2020-03-04T12: 40: 17Z\",\n\t\t\t\t\t\t\"last_vm_scanned_date\": \"2020-03-04T12: 40: 17Z\",\n\t\t\t\t\t\t\"last_vm_scanned_duration\": \"564\",\n\t\t\t\t\t\t\"tagList\": \"Not scanned in 90 days, Internet Facing Assets, OS: Linux x.x, Not scanned in 30 days, Not scanned 120 days, OS: Ubuntu xx, OS: Linux 2.x\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t}\n}\n      \n    \n  }\n]"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        500,
        300
      ],
      "notesInFlow": true,
      "notes": "Mockup"
    },
    {
      "parameters": {
        "functionCode": "const response = items[0].json.host_list_output.response\n\nconst tags = [];\n\nfor (const host of response.host_list.host) {\n  for (const tag of host.tags.tag) {\n    tags.push(tag.name)\n  }\n}\n\nconst data = items[0];\n\ndata.json.host_list_output.response.host_list.host[0][\"tagList\"] = tags.join(',')\n\nreturn [data]\n"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        700,
        300
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Ah, I see. You have to build your new JSON structure within the loop and then return that. Thanks! This explains the approach well.

2 Likes