How to get a proper value from multi-output node?

Hello! I’ve set up a sample workflow where my main function returns four items. I know how to access its value by using SplitInBatches, but I want to know how to make it in a ‘parallel’ way. My sample data has some ids from 1 to 4 and I want to get their corresponding values after the IF node without the relative reference (via $json), but via $node reference. But both my Set nodes return the same data.

Workflow code:

{
  "name": "My workflow",
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "const sample = [\n  {\n    \"json\": {\n      \"name\": \"test_1\",\n      \"pid\": 1\n    }\n  },\n  {\n    \"json\": {\n      \"name\": \"test_2\",\n      \"pid\": 2\n    }\n  },\n  {\n    \"json\": {\n      \"name\": \"test_3\",\n      \"pid\": 3\n    }\n  },\n  {\n    \"json\": {\n      \"name\": \"test_4\",\n      \"pid\": 4\n    }\n  }\n]\n\nreturn sample;"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        500,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{$json[\"pid\"]}}",
              "value2": 3
            }
          ]
        }
      },
      "name": "IF < 3",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        750,
        300
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "test",
              "value": "={{$node[\"Function\"].json[\"name\"]}}"
            }
          ]
        },
        "options": {}
      },
      "name": "Set for 1 and 2",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        1010,
        190
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "test",
              "value": "={{$node[\"Function\"].json[\"name\"]}}"
            }
          ]
        },
        "options": {}
      },
      "name": "Set for 3 and 4",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        1010,
        360
      ]
    },
    {
      "parameters": {},
      "name": "End",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1270,
        280
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "IF < 3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF < 3": {
      "main": [
        [
          {
            "node": "Set for 1 and 2",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set for 3 and 4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set for 1 and 2": {
      "main": [
        [
          {
            "node": "End",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set for 3 and 4": {
      "main": [
        [
          {
            "node": "End",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {}
}

Hey @barn4k,

Welcome to the community :sparkling_heart:

Thank you for providing the example workflow. I ran the workflow and noticed that you’re using the same reference in both the Set nodes. The expression with $node returns the data from the node, irrespective of the condition. Can you please explain why you don’t want to reference the data using $json? It would be helpful if you can explain the use case :slight_smile:

In a more complex scenario, I have some alerts from MS Security API that have an alert_id and a computer_name reference. Then I look for the owner of this computer in the LDAP. After that, I need to send an email with both the alert_id and computer_name to the end-user. So I can’t reference the $json property in the send_email node as I have two different data sources for it (LDAP for the user_email and MS Security for the alert_id and computer_name)

I’ve prepared a more visible example. I want to send an email only if the user is an admin. And the email must have an alert and computer information.

In this example I have 4 alerts (but their ID can be unique strings or uuid):

  • alert id 1 - pc100
  • alert id 2 - pc200
  • alert id 3 - pc300
  • alert id 4 - pc400

In “LDAP” function I have pairs of PC and users:

  • pc100 - Sam
  • pc200 - Tom
  • pc300 - Dave (Admin)
  • pc400 - Bob (Admin)

And my Send Email node has completely messed data. So the only option here is to write some function to compare the data and build the right JSON?

{
  "name": "My workflow",
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        100,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "const sample = [\n  {\n    \"json\": {\n      \"id\": 1,\n      \"name\": \"sample alert1\",\n      \"computerName\": \"pc100.example.com\"\n    }\n  },\n  {\n    \"json\": {\n      \"id\": 2,\n      \"name\": \"sample alert2\",\n      \"computerName\": \"pc200.example.com\"\n    }\n  },\n  {\n    \"json\": {\n      \"id\": 3,\n      \"name\": \"sample alert3\",\n      \"computerName\": \"pc300.example.com\"\n    }\n  },\n  {\n    \"json\": {\n      \"id\": 4,\n      \"name\": \"sample alert4\",\n      \"computerName\": \"pc400.example.com\"\n    }\n  }\n]\n\nreturn sample;"
      },
      "name": "get Alerts from MS",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        300,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "if (item.computerName == \"pc400.example.com\") {\n  return {\n      \"owner_email\": \"[email protected]\",\n      \"owner_name\": \"Bob Bober\",\n      \"is_admin\": true\n    }\n} else  if (item.computerName == \"pc100.example.com\") {\n  return {\n      \"owner_email\": \"[email protected]\",\n      \"owner_name\": \"Sam Bridges\",\n      \"is_admin\": false\n    }\n} else  if (item.computerName == \"pc200.example.com\") {\n  return {\n      \"owner_email\": \"[email protected]\",\n      \"owner_name\": \"Tommy Mc Tom\",\n      \"is_admin\": false\n    }\n} else  if (item.computerName == \"pc300.example.com\") {\n  return {\n      \"owner_email\": \"[email protected]\",\n      \"owner_name\": \"Dave Jason\",\n      \"is_admin\": true\n    }\n}\n"
      },
      "name": "get PC info from LDAP",
      "type": "n8n-nodes-base.functionItem",
      "typeVersion": 1,
      "position": [
        500,
        300
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "userName",
              "value": "={{$json[\"owner_name\"]}}"
            },
            {
              "name": "userEmail",
              "value": "={{$json[\"owner_email\"]}}"
            },
            {
              "name": "alertId",
              "value": "={{$node[\"get Alerts from MS\"].json[\"id\"]}}"
            },
            {
              "name": "computerName",
              "value": "={{$node[\"get Alerts from MS\"].json[\"computerName\"]}}"
            }
          ]
        },
        "options": {}
      },
      "name": "Set data for the Email",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        950,
        200
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$json[\"is_admin\"]}}",
              "value2": true
            }
          ]
        }
      },
      "name": "IF admin",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        700,
        300
      ]
    },
    {
      "parameters": {},
      "name": "Close Alert",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        950,
        400
      ]
    },
    {
      "parameters": {},
      "name": "Send email",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1150,
        200
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "get Alerts from MS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "get Alerts from MS": {
      "main": [
        [
          {
            "node": "get PC info from LDAP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "get PC info from LDAP": {
      "main": [
        [
          {
            "node": "IF admin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF admin": {
      "main": [
        [
          {
            "node": "Set data for the Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Close Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Close Alert": {
      "main": [
        []
      ]
    },
    "Set data for the Email": {
      "main": [
        [
          {
            "node": "Send email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {},
  "id": 18
}

Thank you for sharing this. I am assuming that the get PC info from LDAP node would be an HTTP node to make the API request? If yes, would you be passing the computerName with the API call, or do you make a single API call that returns the information of all the users?

The get PC info from LDAP node is a Lambda function with a python ldap3 module that receives a JSON input for each of the alert entries. So if I have 10 alerts, then it will be 10 LDAP calls

Hey @barn4k,
In that case, the Set node should return the data relevant to that iteration.

I tried out your workflow, and the get PC info from LDAP node and get Alert from MS node do not contain any common data (eg. ID, email, etc.). If both the nodes returned an identical field, you could use the Merge node to merge the node, and then pass it to the next nodes in your workflow.

Ah, I got it. So the best option here is to merge data before IF/Switch nodes and then use a relative path ($json)? As the iteration process starts to get executed differently after those nodes