Quick Question to understand N8n

Hi,

Quick Question.

  1. I have a text data like the one below and i would like that data to be converted as JSON

[
{
“data”: "1] Firing Labels alertname = XX load1 Priority = urgent = 172.16XX.XX:XXX node = ip-172-16-XX.XX.XX region = us-east-1 service = = warning team = nagios Annotations generatorURL = summary = FD Alerts - Device - Kube Node load1 - ip-172-16-XX.XX.XX threshold = 70 to 90 value = 76.04 "
}

]

To something else like

{
“alertname”:“XX load1”,
“Priority”:“urgent”,
“node”:“ip-172-16-XX.XX.XX”
}

Firstly I am not sure, if this is possible with out a fucntion node and secondly how this flow work is, I am using IMAP node to read the email, the email that are been sent are in HTML formate and from the body of the email, we get the above message.

I am trying to convert that information into a JSON.

Please let me know this helps… Feel free, i can gave you more information on the same…

Hi @Sathya_Narayanan, so the values you are interested in are coming through in the data field for each item? Is this binary data or just a field named data in your JSON item (you can read about the difference here in our docs)?

If this is just a field named data, you could convert each item through a Function Item node. I am not particularly great at regular expressions so you might want to optimize this yourself using a tool such as regex101. But assuming the data always appears in the same order and with the same properties (e.g. the value for alertname always appears after "alertname = " and before " Priority = "), something like this should work:

const regexMatches = /alertname\s=\s(.+)\sPriority\s=\s(.+?)\s=\s.*\snode\s=\s(.+)\sregion\s=\s/.exec(item.data);

item.alertname = regexMatches[1];
item.priority = regexMatches[2];
item.node = regexMatches[3];

return item;

Example Workflow:

{
  "nodes": [
    {
      "parameters": {
        "values": {
          "string": [
            {
              "name": "data",
              "value": "1] Firing Labels alertname = XX load1 Priority = urgent = 172.16XX.XX:XXX node = ip-172-16-XX.XX.XX region = us-east-1 service = = warning team = nagios Annotations generatorURL = summary = FD Alerts - Device - Kube Node load1 - ip-172-16-XX.XX.XX threshold = 70 to 90 value = 76.04 "
            }
          ]
        },
        "options": {}
      },
      "name": "Set Example Data",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "const regexMatches = /alertname\\s=\\s(.+)\\sPriority\\s=\\s(.+?)\\s=\\s.*\\snode\\s=\\s(.+)\\sregion\\s=\\s/.exec(item.data);\n\nitem.alertname = regexMatches[1];\nitem.priority = regexMatches[2];\nitem.node = regexMatches[3];\n\nreturn item;"
      },
      "name": "Parse Data",
      "type": "n8n-nodes-base.functionItem",
      "typeVersion": 1,
      "position": [
        650,
        300
      ]
    }
  ],
  "connections": {
    "Set Example Data": {
      "main": [
        [
          {
            "node": "Parse Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Hi,

Thanks for writing back and the workflow, this wont work for my requirement, as i have mentioned the email that we get from monitoring tool will have addtional fields and it wont be on the same set…

some alerts node will be present and in some it wont…

I have tested your code and i end up with an error…

TypeError: Cannot read property '1' of null at /usr/local/lib/node_modules/n8n/node_modules/n8n-nodes-base/dist/nodes:3:30 at Object.<anonymous> (/usr/local/lib/node_modules/n8n/node_modules/n8n-nodes-base/dist/nodes:7:14) at NodeVM.run (/usr/local/lib/node_modules/n8n/node_modules/vm2/lib/main.js:1167:29) at Object.execute (/usr/local/lib/node_modules/n8n/node_modules/n8n-nodes-base/dist/nodes/FunctionItem.node.js:92:41) at Workflow.runNode (/usr/local/lib/node_modules/n8n/node_modules/n8n-workflow/dist/src/Workflow.js:508:37) at /usr/local/lib/node_modules/n8n/node_modules/n8n-core/dist/src/WorkflowExecute.js:442:62 at processTicksAndRejections (internal/process/task_queues.js:93:5)

I am new to this java coding and i was trying to see if there are any other way to formate the data…

This is my payload

[ { "data": "[ { "data": "*[1] Resolved* *Labels* alertname = Throughput(RPM) is high - IND Priority = P2 region = ap-south-1 severity = critical *Annotations* generatorURL = https://metrics.XXXX.es/d/gGB_zwyMz/transaction-XXXX summary = FSA XXX Alerts - Throughput is high- XX-XXX-1 threshold = 20000 value = 29005.275733333317 " } ]" } ]

The function node below should do it.

const results = {}

const data = items[0].json.data.split(' = ')

let key;

for (const [index, element] of data.entries()) {
    if (index === 0) {
        key = element.split(' ')[element.split(' ').length - 1]
        continue;
    } else if ((data.length - 1) === index) {
        const value = element.split('}')[0]
        results[key] = value
    } else {
        const value = element.split(' ').slice(0, element.split(' ').length - 1).join(' ');
        results[key] = value;
    }
    
    key = element.split(' ')[element.split(' ').length - 1]
}

return [
  {
    json: results
  }
]
Example workflow
{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "return [ {\n  json: {\n   \"data\": `[ { \"data\": \"*[1] Resolved* *Labels* alertname = Throughput(RPM) is high - IND Priority = P2 region = ap-south-1 severity = critical *Annotations* generatorURL = https://metrics.XXXX.es/d/gGB_zwyMz/transaction-XXXX summary = FSA XXX Alerts - Throughput is high- XX-XXX-1 threshold = 20000 value = 29005.275733333317 \" } ]`\n  }\n} ]\n"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        550,
        310
      ],
      "notesInFlow": true,
      "notes": "Mockup data"
    },
    {
      "parameters": {
        "functionCode": "const results = {}\n\nconst data = items[0].json.data.split(' = ')\n\nlet key;\n\nfor (const [index, element] of data.entries()) {\n    if (index === 0) {\n        key = element.split(' ')[element.split(' ').length - 1]\n        continue;\n    } else if ((data.length - 1) === index) {\n        const value = element.split('}')[0]\n        results[key] = value\n    } else {\n        const value = element.split(' ').slice(0, element.split(' ').length - 1).join(' ');\n        results[key] = value;\n    }\n    \n    key = element.split(' ')[element.split(' ').length - 1]\n}\n\nreturn [\n  {\n    json: results\n  }\n]\n\n"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        800,
        310
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
1 Like

Hi Ricardo,

Thanks and this is what i was look for, i have one more question and it might sound lame ( I am new to javascript and i did not find any reference to it )…

In my work flow the actual data is set in SET node, how can i call that data into the function ?

i tired the below but i am getting an error message, not sure whats wrong and did refer the community tab for similar conditions…

return [ { json: { "data":{{$node[\"Set\"].data[\"data\"]}} } } ]
Error

/usr/local/lib/node_modules/n8n/node_modules/n8n-nodes-base/dist/nodes:3 "data":{{$node[\"Set\"].data[\"data\"]}}

the value for the data inside the fucntion has to be passed from previous set node and i am trying to find a way as to how to do that… I am still hunting for the answers and though i can ask the experts here.

I think i got it but not sure if that the right way…

I tried to access the $items of Set node on the function and got the previous nodes output…

return [ { json: { "data": $items("Set") } } ]

And out put is

[ { "data": [ { "json": { "data":[ { "data": "*[1] Resolved* *Labels* alertname = Throughput(RPM) is high - IND Priority = P2 region = ap-south-1 severity = critical *Annotations* generatorURL = https://metrics.XXXX.es/d/gGB_zwyMz/transaction-XXXX summary = FSA XXX Alerts - Throughput is high- XX-XXX-1 threshold = 20000 value = 29005.275733333317 " } ]
}
} ]
`
Do we have to make any modification on the second fucntion which you mentioned on your work flow ?

I assume this data is coming from an HTTP node. Can I see the output of the HTTP? That way, I can adjust the function node.

Please find the code below.

{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "postProcessAction": "nothing",
        "options": {
          "allowUnauthorizedCerts": true
        }
      },
      "name": "IMAP Email",
      "type": "n8n-nodes-base.emailReadImap",
      "typeVersion": 1,
      "position": [
        480,
        330
      ],
      "credentials": {
        "imap": "IMAP account"
      }
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "data",
              "value": "={{$node[\"IMAP Email\"].json[\"textPlain\"]}}"
            }
          ]
        },
        "options": {
          "dotNotation": true
        }
      },
      "name": "Set",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        680,
        330
      ]
    },
    {
      "parameters": {
        "functionCode": "return [{\n   json:{\n      \"data\": $node[\"Set\"].data[\"data\"]\n      }\n    }\n  ]\n\n"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        910,
        330
      ]
    },
    {
      "parameters": {
        "functionCode": "const results = {}\n\nconst data = items[0].json.data.split(' = ')\n\nlet key;\n\nfor (const [index, element] of data.entries()) {\n    if (index === 0) {\n        key = element.split(' ')[element.split(' ').length - 1]\n        continue;\n    } else if ((data.length - 1) === index) {\n        const value = element.split('}')[0]\n        results[key] = value\n    } else {\n        const value = element.split(' ').slice(0, element.split(' ').length - 1).join(' ');\n        results[key] = value;\n    }\n    \n    key = element.split(' ')[element.split(' ').length - 1]\n}\n\nreturn [\n  {\n    json: results\n  }\n]\n\n"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        1110,
        330
      ]
    }
  ],
  "connections": {
    "IMAP Email": {
      "main": [
        [
          {
            "node": "Set",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

I am using IMAP to gather the info from a mail and the mail has HTML content (alert) and i am trying to use the text method to get only the plan text of the content and process it further…

Can you show me exactly what the set node returns? Run the workflow and attach a picture, please.

Please find the screenshot of the SET node.

The function node should not need any chance with that output. Check the example below, and you will notice it works with the same output as the set node you shared.

{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "return [ {\n  json: {\n   \"data\": `*[1] Resolved* *Labels* alertname = Throughput(RPM) is high - IND Priority = P2 region = ap-south-1 severity = critical *Annotations* generatorURL = https://metrics.XXXX.es/d/gGB_zwyMz/transaction-XXXX summary = FSA XXX Alerts - Throughput is high- XX-XXX-1 threshold = 20000 value = 29005.275733333317`\n  }\n} ]\n"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        490,
        300
      ],
      "notesInFlow": true,
      "notes": "Mockup data"
    },
    {
      "parameters": {
        "functionCode": "const results = {}\n\nconst data = items[0].json.data.split(' = ')\n\nlet key;\n\nfor (const [index, element] of data.entries()) {\n    if (index === 0) {\n        key = element.split(' ')[element.split(' ').length - 1]\n        continue;\n    } else if ((data.length - 1) === index) {\n        const value = element.split('}')[0]\n        results[key] = value\n    } else {\n        const value = element.split(' ').slice(0, element.split(' ').length - 1).join(' ');\n        results[key] = value;\n    }\n    \n    key = element.split(' ')[element.split(' ').length - 1]\n}\n\nreturn [\n  {\n    json: results\n  }\n]\n\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
          }
        ]
      ]
    }
  }
}

Hi,

Yes the function node works perferctly fine when the data is hardcoded into it… like below…

however what i am trying to achieve is , the data in that function node should get dynamic value from the previous SET node and that is where its not working…

I am trying to do something like this on the function node with out hardcoding the actual data response…

The above code gives me a response on the function node as …

and the last function node give me a response like this…

I have shared the entire workflow with screenshots…

The function node gets the data dynamically, as long as it’s connected after the Set node. What seems to have happened, it’s that this string has a URL with query string values that also use =, which is the value I use to split the string. The string has to be pre-processed to encode all URLs if there is one in the string.

Alrite, I tried with another set of alert which does not have that URL problem, even in that i am having the same issue…

Payload

[ { "data": ""data": "*[1] Firing* *Labels* alertname = Kube Check Pods - haystack_use1 Priority = P2 app_kubernetes_io_name = kube-state-metrics container = haystack-trace-shipper controller_kind = ReplicaSet controller_name = kube-state-metrics-69c9ddc78 instance = 10.50.131.62:8080 job = k8s/kube-state-metrics k8s_app = kube-state-metrics k8s_cluster_name = freshsales-eks-us namespace = haystack node = ip-10-50-141-210.ec2.internal pod = haystack-trace-shipper-wr9jn pod_template_hash = 69c9ddc78 region = us-east-1 severity = warning team = nagios "" } ]

Here are my observations.

if i hardcode the payload into the function which calls the json.data i am getting the expected result. Please refer the screeen shot below.

This is only when i hard code the payload in the function…

I run the same set of data on my stage which doesnt have the payload hardcoded where as i am calling it using the $[node] function and my results are completely different… Please refer the screen shot below.

function 1:

function2 the actual output:

I seriously think there is something wrong that i am making in calling the payload on function 1

That is weird because function one as you have it should still work. What I do not get is why you need the set function at all? Can you just connect the function I provided to the IMAP node?

Yes I tried even that din work

On the function 1 I pointed that data part to the node which runs the imap and filtered the text value to process it… It din work either…

I used set here just to filter the content I am interested on… Set has no other value other than storing my reaults as a variable…

Hey,

I got that working, providing the solution here fror others who might have similar issue…

The problem was when i send the data to the function, there were lot of new line charcteres(/n) and becuase of this the function was failing…

what i have done is, in the function 1.i added the new line removal…

const check = $node["Email"].data["textPlain"] var check1 = check.replace(/(\r\n|\n|\r)/gm, " "); return [{ json: { "data": check1 } }]

this solved the issue and now i am getting the text in json…

Now that i am trying to make one more change in the code where, i have to add one more field in the json which should say the Label… these values are already avaiable in the payload as

"[1] Firing Labels alertname =

how can i have this field added to the json ?

1 Like

Hi @Sathya_Narayanan, I am not sure I fully understand your last question, so maybe you can help me out here. So your real-world output now also looks like this:

image

And this is (mostly) what you wanted to see.

Now the open point would be to have one additional field “label” with a value of “alertname”? Our should the value of the label field be “Kube Check Pods - haystack_use1” in this instance (meaning you essentially just want to rename the first field)?

Maybe you can share your expected output?