Problem with Workflow using IF and access to previous nodes

Hi N8N community,

first of all thanks for this great tool - it looks really promising and we try to setup some first workflows which looks very promising and runs quite well.

I have just one problem which I can’t get resolved - trying the following to achieve:

  1. Get records from MySQL
  2. Query REST API and find out if this record exists already
  3. IF → true → update record using REST API / false → create record using REST API

The second REST call has to use the data from the MYSQL node to create the request and I’m using the following expression to create the REST data for the second call:

{ “client” : {
“number”: “{{$node[“Get All Companies”].json[“company_code”]}}”,
}}

However the problem now is that the false tree also uses the first record of the MYSQL node and customer_code CN-1170 instead of CN-1171 which would be the second row from the MYSQL result set.

Read all the documentation several times and searched the forum but maybe I have a basic misunderstanding how things are working?

Thanks a lot,
Jonas

Attached:

  • Workflow image
  • MySQL result
  • Billomat Check
  • If definition
  • If result true
  • If result false
  • HTTP Request on the false branch (should be number CN-1171 from the second data row and not CN-1170 which is routed to the TRUE branch)

Hey, @jsextl welcome to the community. The example below should fix the issue you are having. If something is not clear enough or you have any other questions, simply come back to me. Have fun.

{
  "nodes": [
    {
      "parameters": {
        "functionCode": "return [\n  {\n    json: {\n      company_code: 1\n    }\n  },\n    {\n    json: {\n      company_code: 2\n    }\n  },\n      {\n    json: {\n      company_code: 3\n    }\n  }\n]"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        510,
        300
      ],
      "notesInFlow": true,
      "notes": "Get all companies mockup"
    },
    {
      "parameters": {
        "functionCode": "return [\n  {\n    json: {\n      id: 1,\n      exist: true,\n    }\n  },\n    {\n    json: {\n      id: 2,\n      exist: false\n    }\n  },\n      {\n    json: {\n      id: 3,\n      exist: true\n    }\n  }\n]"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        820,
        180
      ],
      "notesInFlow": true,
      "notes": "Check Billomat mockup"
    },
    {
      "parameters": {
        "mode": "mergeByIndex"
      },
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 1,
      "position": [
        1090,
        280
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$node[\"Merge\"].json[\"exist\"]}}",
              "value2": true
            }
          ]
        }
      },
      "name": "IF",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        1360,
        280
      ]
    },
    {
      "parameters": {},
      "name": "NoOp",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1580,
        170
      ]
    },
    {
      "parameters": {},
      "name": "NoOp1",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1580,
        410
      ]
    }
  ],
  "connections": {
    "Function": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Function1": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "IF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF": {
      "main": [
        [
          {
            "node": "NoOp",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "NoOp1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
1 Like

Hi Ricardo,
first of all thank you very much for the quick reply - it is working now with the merge - can you quickly explain to me why my version did not work?

And I still need those two NoOp Nodes between IF and HTTP_REQUEST on the right side - otherwise the HTTP Request does get the wrong input if I use {{$node[“IF”].json[“company_code”]}} to create the request data - is that by design or is there a way to get rid of the NoOps?

Working workflow attached for reference.

Best regards,
Jonas

For what was wrong, we have to wait for Ricardo, else I have to reconstruct it again now myself. But about why the NoOp nodes are needed I can answer. It should not be needed for the “true” path but for the “false” one because expressions use by default the data the node outputs from the first output.
A way around that would be to use instead of:

{{$node[“IF”].json[“company_code”]}}

this:

{{$json[“company_code”]}}

That will simply use the data the not did receive as input and should then work without the NoOp nodes.

Hi Jan,
thanks for explanation - indeed {{$json[“company_code”]}} does work - I was just confused because you cannot select {{$json[“company_code”]}} in the GUI - if I navigate the nodes tree and select something it always uses the syntax $node[…].json - even if I chose “Current Node / Input data / …” - maybe this can changed it would make things more clear and working by default.
Best regards,
Jonas

Yes agree. The $json is currently not documented yet as I remember that there were still some edge-cases where it caused problems. In the future it should for sure use that syntax if possible. That will then be part of the Expression-Editor overhaul that is planned.

Hey @jsextl, to be honest, you did what I had done. It took me some time to figure it out since I did not know the existence of the $json. I was going to ask Jan today about that behavior. The only thing I did differently was using the merge node to have all the data needed as the input to the IF node so that you did not have to use the expression to reference the country_code on the MySQL node but to reference country_code from the if node output. Your version did not work because, as far as I know, the expressions use input length of the node where they are defined (in your case the HTTP node) to reference the data on other nodes, and the IF node was always outputting one element to the HTTP node, thus the expression on it was referencing the first position in the output of the MySQL node.

Hi Jan,
ok perfect - now I know how to do it and if the GUI does it sometime in the future even better :slight_smile:
Best regards,
Jonas

Hi Ricardo,
thanks now I have a little more understanding.

So as far as I understand there is no easy way to access the data of a parent node in front of the IF node?

I think what would be really useful would be a visual view / schema of the data-flow / processing logic in the documentation - I read the docs several times but at the and I had no real understanding how things are processed and how all this logic with the nodes and the data arrays, etc. is working - especially in case “IF” nodes are used to split the data.

Maybe for the future it would also good to have some Workflow patterns in the documentation outlining those design patterns behind the workflow logic - I think that would be very useful to get an overall understanding of the logic.

Best regards,
Jonas

@jsextl Sorry for the late response somehow, I missed this response.

You can access the data of the parents’ nodes of a node in front of the IF node, but as probably the input of the true and false path is not going to match the length of the parent node output, you want to get data from, you will get the wrong data. Check the example below.

Thanks for the feedback, and yes, the documentation is something that needs improvements, we are working on it. We are a small team with a bunch of tasks. I do agree with you on how the data flow is KEY to understand n8n. Actually, that was confusing to me at the beginning.

On the hosted version we are probably going to have a datastore node where you can save and retrieve data at any point in the workflow that will come handy on those scenarios.

{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        260,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "return [\n      {\n    json: {\n      company_code: 3,\n    }\n  },\n    {\n    json: {\n      company_code: 2,\n    }\n  },\n  {\n    json: {\n      company_code: 1,\n    }\n  },\n\n]"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        520,
        300
      ],
      "notesInFlow": true,
      "notes": "Get all companies mockup"
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$node[\"Function1\"].json[\"pass\"]}}",
              "value2": true
            }
          ]
        }
      },
      "name": "IF",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        930,
        300
      ]
    },
    {
      "parameters": {
        "requestMethod": "POST",
        "url": "https://webhook.site/3786832a-7b75-43bb-a71f-3156a4c76526",
        "options": {},
        "bodyParametersUi": {
          "parameter": [
            {
              "name": "id",
              "value": "={{$node[\"Function\"].json[\"company_code\"]}}"
            },
            {
              "name": "false",
              "value": "false"
            }
          ]
        }
      },
      "name": "HTTP Request1",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 1,
      "position": [
        1290,
        460
      ]
    },
    {
      "parameters": {
        "functionCode": "return [\n      {\n    json: {\n      pass: true,\n    }\n  },\n    {\n    json: {\n      pass: false,\n    }\n  },\n  {\n    json: {\n      pass: true,\n    }\n  },\n\n]\n"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        740,
        300
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF": {
      "main": [
        null,
        [
          {
            "node": "HTTP Request1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function1": {
      "main": [
        [
          {
            "node": "IF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Hi Ricardo,
thanks for the clarification - I think I understand it now.
From a user perspective it would make sense to have something like a $parent array to always access the data of the currently processed run - but I assume that is difficult, because you have merge operation for example and therefore $parent would not always be defined properly, right?
Will that datastore node be possible in the self-hosted version as well?
Best regards,
Jonas

Hey, @jsextl. Yeah, having a $parent seems to be a good idea. To be honest, I have no idea how difficult it can be to add. That is a core feature a most of my experience is related to integrations.

About the datastore, I guess we will have something generic for the self-hosted version like a Redis node that adds and retrieves information during the workflow.