Access key values inside Array (POST webhook from parsio.io)

Hello, I receive the following data as JSON via POST webhook from parsio.io:

[
  {
    "headers": {
      "host": "whatever",
      "..."
    },
    "params": {},
    "query": {},
    "body": {
      "mailbox_id": "619d0976b84dc20011f279c7",
      "doc_id": "619d0d6db84dc20011f27fb6",
      "event": "doc.parsed",
      "payload": {
        "template_id": "619d0ee7b84dc20011f27fdc",
        "parsed": [
          {
            "name": "Supply",
            "value": "Foo"
          },
          {
            "name": "Number",
            "value": "00xxxxxxx"
          },
          {
            "name": "Date",
            "value": "10/05/2021"
          },
          {
            "name": "Address",
            "value": "Street"
          },
          {
            "name": "Amount",
            "value": "0,71"
          },
          {
            "name": "Due",
            "value": "31/05/2021"
          },
          {
            "name": "Supplier",
            "value": "Foo"
          },
          {
            "name": "received_at_date",
            "value": "2021-11-23"
          },
          {
            "name": "attachments_nb",
            "value": 1
          }
        ]
      }
    }
  }
]

and try to send it to Airtable. I use set to define the fields I want to write. The problem actually is that inside set I need to access each field I need this way {{$json["body"]["payload"]["parsed"][X]["value"]}} where X is the position in the parsed[] array. Thing is this position changes from request to request so I would like to access those values using key values. I’m trying to use function node before in order to map this in some way (this is just testing code):

// var keys = Object.keys($json["body"]["payload"]["parsed"]);
// var item = $json["body"]["payload"]["parsed"]

// const newArr = arr.map(obj => Object.values(obj));
// var keys = Object.keys(item.json);
// console.log(keys);

const data = items.map((item) => item.json);

return [
  {
    json: {
      cells: data
      // cells: keys
    }
  }
]

Any suggestions? Maybe I don’t even need to use the function node at all and just need to access {{$json["body"]["payload"]["parsed"][X]["value"]}} in the correct way inside set node. Thanks

Hi @eim, I can’t think of an elegant way to solve this without a JS snippet (though you can probably get this to work by using the Item Lists node to spread out the body.payload.parsed array and then use a bunch of IF nodes to filter for each name and then merge it all together).

But JS code might be easier in this case. I assume you want to see each of the values inside body.payload.parsed in their own fields?

If so, you could try something like this in your Function node:

for (item of items) {
  for (field of item.json.body.payload.parsed) {
    item.json[field.name] = field.value;
  }
}

return items;

This example snippet would run through each item and then through each of the objects inside item.json.body.payload.parsed and adds them as a new field to the item itself.

Here’s an example workflow showing the approach:

Example Workflow
{
  "nodes": [
    {
      "parameters": {
        "functionCode": "for (item of items) {\n  for (field of item.json.body.payload.parsed) {\n    item.json[field.name] = field.value;\n  }\n}\n\nreturn items;"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        650,
        300
      ]
    },
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "const example = [\n  {\n    \"headers\": {\n      \"host\": \"whatever\",\n    },\n    \"params\": {},\n    \"query\": {},\n    \"body\": {\n      \"mailbox_id\": \"619d0976b84dc20011f279c7\",\n      \"doc_id\": \"619d0d6db84dc20011f27fb6\",\n      \"event\": \"doc.parsed\",\n      \"payload\": {\n        \"template_id\": \"619d0ee7b84dc20011f27fdc\",\n        \"parsed\": [\n          {\n            \"name\": \"Supply\",\n            \"value\": \"Foo\"\n          },\n          {\n            \"name\": \"Number\",\n            \"value\": \"00xxxxxxx\"\n          },\n          {\n            \"name\": \"Date\",\n            \"value\": \"10/05/2021\"\n          },\n          {\n            \"name\": \"Address\",\n            \"value\": \"Street\"\n          },\n          {\n            \"name\": \"Amount\",\n            \"value\": \"0,71\"\n          },\n          {\n            \"name\": \"Due\",\n            \"value\": \"31/05/2021\"\n          },\n          {\n            \"name\": \"Supplier\",\n            \"value\": \"Foo\"\n          },\n          {\n            \"name\": \"received_at_date\",\n            \"value\": \"2021-11-23\"\n          },\n          {\n            \"name\": \"attachments_nb\",\n            \"value\": 1\n          }\n        ]\n      }\n    }\n  }\n]\nreturn example.map(e => {return {json: e}});"
      },
      "name": "Set Example Data",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "for (item of items) {\n  for (field of item.json.body.payload.parsed) {\n    item.json[field.name] = field.value;\n  }\n}\n\nreturn items;"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        650,
        300
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Set Example Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Example Data": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

It would return data like this (you might want to throw away headers, body etc. if no longer needed to keep your items more readable):

Is this what you had in mind?

1 Like

Thank you very much @MutedJam, this looks really good so far and works;)
In case I would like to discard the other values I’m trying something like this:

var r = [];

for (item of items) {
  for (field of item.json.body.payload.parsed) {
    r[field.name] = field.value;
  }
}

return r;

how would you do this? Using a second object and copy items over? Thanks

So there are a couple of ways that’d work. What you have suggested would do the trick, you’d just need to create the new object first (keeping n8n’s data structure in mind) and then assign the values before pushing it to your results array r. Like so:

var r = [];

for (item of items) {
  let my_new_item = {json: {}};
  for (field of item.json.body.payload.parsed) {
    my_new_item.json[field.name] = field.value;
  }
  r.push(my_new_item);
}

return r;

Or you could stick with the example from my previous post and just delete the properties you no longer need:

for (item of items) {
  for (field of item.json.body.payload.parsed) {
    item.json[field.name] = field.value;
    delete item.json.body;
  }
}

return items;

Or as a code-free approach you could put a Set node after your Function node and enable the Keep Only Set option, then defining each field you want to keep:

2 Likes

Perfect, thank you very much @MutedJam

1 Like