Data transformation

Quick question,

How do you turn this data structure into a format that n8n can use in a function node to iterate over?


[
{
"ONE": [
"aaa",
"bbb",
"ccc",
"ddd",
"eee"
],
"TWO": [
"fff",
"ggg",
"hhh",
"iii",
"jjj",
"kkk",
"lll",
"mmm",
"nnn",
"ooo"
],
"THREE": [
"ppp",
"qqq",
"rrr",
"sss",
"ttt"
]
}
]

i looked here, but couldn’t get it to work

Hey @RedPacketSec!

Do you want to iterate over the nested array items? Or do you want to iterate over the fields ONE, TWO, etc?

The nested array items

return [].concat(...Object.values(items[0].json[0])).map(i => ({ json: { str: i } }))

That is neat, I was going the long way with it and set a function to return it that had…

return [{json:{"ONE": ["aaa","bbb","ccc","ddd","eee"],"TWO": ["fff","ggg","hhh","iii","jjj","kkk","lll","mmm","nnn","ooo"],"THREE": ["ppp","qqq","rrr","sss","ttt"]}}];

Then used a second function to iterate over it which contained…

for(var i = 0; i < items.length; i++) {
  console.log(items[i].json); // This is your objects (ONE, TWO, THREE)
  var foo = items[i].json; // Just for convenience
  for (bar in foo) { // Loop each object
    console.log(foo[bar]) // This gives you the arrays
    for (var j = 0; j < foo[bar].length; j++) {
      console.log(foo[bar][j]); // This is your single array item
    }
  }
}

return items;
1 Like

objectObject

Here is the function in a working sample. You will need to adjust to your existing workflow.

{
  "name": "Aug 25 sample workflow",
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        270,
        290
      ]
    },
    {
      "parameters": {
        "functionCode": "return [\n\t\t{\n\t\t\tjson: [\n\t\t\t\t{\n\t\t\t\t\t\"ONE\": [\n\t\t\t\t\t\t\"aaa\",\n\t\t\t\t\t\t\"bbb\",\n\t\t\t\t\t\t\"ccc\",\n\t\t\t\t\t\t\"ddd\",\n\t\t\t\t\t\t\"eee\"\n\t\t\t\t\t],\n\t\t\t\t\t\"TWO\": [\n\t\t\t\t\t\t\"fff\",\n\t\t\t\t\t\t\"ggg\",\n\t\t\t\t\t\t\"hhh\",\n\t\t\t\t\t\t\"iii\",\n\t\t\t\t\t\t\"jjj\",\n\t\t\t\t\t\t\"kkk\",\n\t\t\t\t\t\t\"lll\",\n\t\t\t\t\t\t\"mmm\",\n\t\t\t\t\t\t\"nnn\",\n\t\t\t\t\t\t\"ooo\"\n\t\t\t\t\t],\n\t\t\t\t\t\"THREE\": [\n\t\t\t\t\t\t\"ppp\",\n\t\t\t\t\t\t\"qqq\",\n\t\t\t\t\t\t\"rrr\",\n\t\t\t\t\t\t\"sss\",\n\t\t\t\t\t\t\"ttt\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t]"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        430,
        290
      ]
    },
    {
      "parameters": {
        "functionCode": "return [].concat(...Object.values(items[0].json[0])).map(i => ({ json: { str: i } }))"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        590,
        290
      ]
    }
  ],
  "connections": {
    "Function": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {},
  "id": 233
}

So that works in your example.

I guess if i mock it up in google sheets, i’m more looking for this
image

Where as your flow that works give me this

does that maybe help explain it better?

@RedPacketSec so your want to merge everything?

My second function snippet would do it if you add an array and push each item to it where the console.log is.

yeah im extracting html data from a website with say 3 entries

one = name
two = url
three - content for example

so they need to align when iterating if that makes sense

name URL content
aaa bbb ccc
ddd eee ffff

if that makes sense?

just looked at some old flows that do something similar and i think its going to be close to this

return [].concat(
	...items.map(i => i.json.objects.map(o => {
		return { json: { ...o, name: i.json.name , website: i.json.website } };
	}))
);

but i need to tweak it to get rid of this
image

What you need is a function like this:

const data = items[0].json[0];

const response = [];

for (const [key, values] of Object.entries(data)) {
  for (const [index, element] of values.entries()) {
      if (response[index] === undefined) {
        response[index] = { }
      }
      response[index][key] = element
  }
}

return response.map((data) => ({ json: data }))
Example workflow
{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "return [\n\t\t{\n\t\t\tjson: [\n\t\t\t\t{\n\t\t\t\t\t\"ONE\": [\n\t\t\t\t\t\t\"aaa\",\n\t\t\t\t\t\t\"bbb\",\n\t\t\t\t\t\t\"ccc\",\n\t\t\t\t\t\t\"ddd\",\n\t\t\t\t\t\t\"eee\"\n\t\t\t\t\t],\n\t\t\t\t\t\"TWO\": [\n\t\t\t\t\t\t\"fff\",\n\t\t\t\t\t\t\"ggg\",\n\t\t\t\t\t\t\"hhh\",\n\t\t\t\t\t\t\"iii\",\n\t\t\t\t\t\t\"jjj\",\n\t\t\t\t\t\t\"kkk\",\n\t\t\t\t\t\t\"lll\",\n\t\t\t\t\t\t\"mmm\",\n\t\t\t\t\t\t\"nnn\",\n\t\t\t\t\t\t\"ooo\"\n\t\t\t\t\t],\n\t\t\t\t\t\"THREE\": [\n\t\t\t\t\t\t\"ppp\",\n\t\t\t\t\t\t\"qqq\",\n\t\t\t\t\t\t\"rrr\",\n\t\t\t\t\t\t\"sss\",\n\t\t\t\t\t\t\"ttt\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t]"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "const data = items[0].json[0];\n\nconst response = [];\n\nfor (const [key, values] of Object.entries(data)) {\n  for (const [index, element] of values.entries()) {\n      if (response[index] === undefined) {\n        response[index] = { }\n      }\n      response[index][key] = element\n  }\n}\n\nreturn response.map((data) => ({ json: data }))"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        690,
        300
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
2 Likes

That is going into my notes :+1:

so that works perfectly in your example workflow, why does it error out when you attach it to the HTML extract node?

Do I need to pipe the HTML extract into something else? or reference the specific node in the function node script?

Because the input you presented first it’s different.

Change the first line of the function node to:

const data = items[0].json

oh im sorry, I copied and pasted the format, must have messed it up sorry for messing you around :frowning: :no_mouth:

that works perfectly, thank you so much

solution:

const data = items[0].json;

const response = [];

for (const [key, values] of Object.entries(data)) {
  for (const [index, element] of values.entries()) {
      if (response[index] === undefined) {
        response[index] = { }
      }
      response[index][key] = element
  }
}

return response.map((data) => ({ json: data }))
1 Like