{
  "id": "qOAgdqA9CYJiMqJl",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "TEMPLATE Nested folder recursion",
  "tags": [],
  "nodes": [
    {
      "id": "8fb482bf-81df-48de-b4c0-a04c3a31891d",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -416,
        -592
      ],
      "parameters": {
        "color": 6,
        "width": 1040,
        "height": 496,
        "content": "### Sets root folder to monitor and trigger recursive workflow"
      },
      "typeVersion": 1
    },
    {
      "id": "7657a4a5-9d4c-4c15-83f6-2edf8a40cca3",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -416,
        -80
      ],
      "parameters": {
        "color": 6,
        "width": 1040,
        "height": 448,
        "content": "### Recursively iterates through all nested folders and list their files"
      },
      "typeVersion": 1
    },
    {
      "id": "02300ebf-8389-4a7b-ba79-1977202327ba",
      "name": "Loop all subfolders",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -96,
        128
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "3f55820c-f4f0-40fb-ac32-4e62b43ea196",
      "name": "List folders",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        128,
        128
      ],
      "parameters": {
        "filter": {
          "folderId": {
            "__rl": true,
            "mode": "id",
            "value": "={{ $json.id }}"
          },
          "whatToSearch": "folders"
        },
        "options": {},
        "resource": "fileFolder",
        "returnAll": true
      },
      "typeVersion": 3,
      "alwaysOutputData": true
    },
    {
      "id": "572e0740-0bec-469d-8f4f-9eec8edb9439",
      "name": "If subfolders exist",
      "type": "n8n-nodes-base.if",
      "position": [
        272,
        128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "e6a6144c-5c3d-4c15-92e7-147787ece96c",
              "operator": {
                "type": "object",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "9620aee5-78dc-424c-a68e-78c66e67cd51",
      "name": "Trigger recursion to next level",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        464,
        128
      ],
      "parameters": {
        "options": {},
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $workflow.id }}"
        },
        "workflowInputs": {
          "value": {},
          "schema": [
            {
              "id": "folder_name",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "folder_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "folder_name"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "e1f951c5-8abd-4f08-ae78-49f20f12c811",
      "name": "List folders in root",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -64,
        -464
      ],
      "parameters": {
        "filter": {
          "folderId": {
            "__rl": true,
            "mode": "list"
          },
          "whatToSearch": "folders"
        },
        "options": {},
        "resource": "fileFolder",
        "returnAll": true
      },
      "typeVersion": 3,
      "alwaysOutputData": true
    },
    {
      "id": "77e0374f-38cf-4788-9ed6-8af4ad672294",
      "name": "List all files in root",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -64,
        -272
      ],
      "parameters": {
        "filter": {
          "folderId": {
            "__rl": true,
            "mode": "list"
          },
          "whatToSearch": "files"
        },
        "options": {
          "fields": [
            "*"
          ]
        },
        "resource": "fileFolder",
        "returnAll": true
      },
      "executeOnce": true,
      "typeVersion": 3,
      "alwaysOutputData": true
    },
    {
      "id": "4c07501b-6989-42c5-82ff-f15793e56f84",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -112,
        -544
      ],
      "parameters": {
        "color": 3,
        "width": 288,
        "height": 432,
        "content": "## Instruction: \n### Define root folder in both of these"
      },
      "typeVersion": 1
    },
    {
      "id": "6e141c99-9142-4480-9b31-c5eafcb387ec",
      "name": "Start recursion",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        -368,
        -16
      ],
      "parameters": {
        "inputSource": "passthrough"
      },
      "typeVersion": 1.1
    },
    {
      "id": "a1d1343a-b0a4-417c-8442-eabec70cb71d",
      "name": "Trigger recursion of first level",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        224,
        -464
      ],
      "parameters": {
        "options": {
          "waitForSubWorkflow": true
        },
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $workflow.id }}"
        },
        "workflowInputs": {
          "value": {},
          "schema": [
            {
              "id": "folder_name",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "folder_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "folder_name"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "executeOnce": false,
      "typeVersion": 1.2
    },
    {
      "id": "5b229c5c-5662-460e-a221-19a02efd8863",
      "name": "List all files",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        272,
        -32
      ],
      "parameters": {
        "filter": {
          "folderId": {
            "__rl": true,
            "mode": "id",
            "value": "={{ $json.id }}"
          },
          "whatToSearch": "files"
        },
        "options": {
          "fields": [
            "*"
          ]
        },
        "resource": "fileFolder",
        "returnAll": true
      },
      "typeVersion": 3
    },
    {
      "id": "f6099368-fe4a-4360-9bf6-f7654b1c6a60",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        -592
      ],
      "parameters": {
        "width": 384,
        "height": 496,
        "content": "### Outputs batches of files created or updated since the last PRODUCTION execution\n*Outputs all files of all nested folders on the first execution*"
      },
      "typeVersion": 1
    },
    {
      "id": "26a7b645-fac2-4f56-94da-d3f447b91d6a",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -368,
        -384
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 60
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f0e363fe-c83c-47ff-bffd-7368ac9874b5",
      "name": "SetStartTime",
      "type": "n8n-nodes-base.code",
      "position": [
        416,
        -272
      ],
      "parameters": {
        "jsCode": "// Get the last execution timestamp from static data\nconst workflowStaticData = $getWorkflowStaticData('global');\nconst executionStart = $('Schedule Trigger').first().json.timestamp;\n\n// At the end of successful execution, update the timestamp for future comparison\nworkflowStaticData.lastScheduleExecutionStarted = new Date(executionStart).getTime();\n\nreturn [{ json: { lastScheduleExecutionStarted: workflowStaticData.lastScheduleExecutionStarted } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "d53c8060-c97f-4577-a151-4690030cb23f",
      "name": "Outputs new or updated files",
      "type": "n8n-nodes-base.code",
      "position": [
        800,
        -432
      ],
      "parameters": {
        "jsCode": "const recentlyChanged = [];\nconst workflowStaticData = $getWorkflowStaticData('global');\nlet lastScheduleExecutionStarted = workflowStaticData.lastScheduleExecutionStarted;\n\n// Set fallback in case this is the first execution that should return all files found\nif (!lastScheduleExecutionStarted) {\n  lastScheduleExecutionStarted = new Date('2010-01-01').getTime();\n}\n\n// Compare created and update timestamps of each file to see if it's later than the last workflow execution\nfor (const item of $input.all()) {\n  if ( (new Date(item.json.modifiedTime).getTime() > lastScheduleExecutionStarted ) || ( new Date(item.json.createdTime).getTime() > lastScheduleExecutionStarted ) ){\n    recentlyChanged.push(item);\n  }\n}\n\nreturn recentlyChanged;"
      },
      "typeVersion": 2
    },
    {
      "id": "80b1a63f-dfac-4422-8778-d0624b6a5fac",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        -80
      ],
      "parameters": {
        "color": 5,
        "width": 384,
        "height": 448,
        "content": "## Information\nTemplate created by Smultron Studio (https://smultronstudio.com/en) - feel free to reach out at hello@smultronstudio.com\n\n### Instructions:\n* Set schedule interval in the Schedule Trigger node\n* Connect the Google Drive nodes with your credentials\n* Set your root folder in the two Google Drive nodes in the red box\n\nPlease note that upon the first execution and any manual executions prior to the first **production execution** this will output all files in all folders. \n\nThis workflow will request both a *file listing* and a *folder listing* in the root folder and **ALL** subfolders, may have performance issues when used on huge folder structures. Keep in mind when setting the trigger time."
      },
      "typeVersion": 1
    },
    {
      "id": "728dce31-efc1-44ee-b626-7674c86aaea4",
      "name": "If folders exist",
      "type": "n8n-nodes-base.if",
      "position": [
        -224,
        -16
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5803397c-7522-4d2c-8118-a8d3da9500df",
              "operator": {
                "type": "object",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2,
      "alwaysOutputData": false
    },
    {
      "id": "17c0b075-9784-4bba-9f5d-d0f00f851271",
      "name": "Exit sub workflow",
      "type": "n8n-nodes-base.set",
      "position": [
        -48,
        -32
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "7dbc41c8-9e5b-4def-bfc4-8fe9e024d70d",
              "name": "status",
              "type": "string",
              "value": "No folders found"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f2123228-8530-4dc6-8cbb-264bfd7efa3c",
      "name": "Wait for file comparison to complete",
      "type": "n8n-nodes-base.wait",
      "position": [
        256,
        -240
      ],
      "parameters": {},
      "typeVersion": 1.1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "93075173-0789-47dd-8b14-bf6fccfa097d",
  "connections": {
    "List folders": {
      "main": [
        [
          {
            "node": "If subfolders exist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SetStartTime": {
      "main": [
        []
      ]
    },
    "List all files": {
      "main": [
        [
          {
            "node": "Outputs new or updated files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start recursion": {
      "main": [
        [
          {
            "node": "If folders exist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If folders exist": {
      "main": [
        [
          {
            "node": "Loop all subfolders",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Exit sub workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "List folders in root",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If subfolders exist": {
      "main": [
        [
          {
            "node": "Trigger recursion to next level",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop all subfolders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop all subfolders": {
      "main": [
        [],
        [
          {
            "node": "List folders",
            "type": "main",
            "index": 0
          },
          {
            "node": "List all files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List folders in root": {
      "main": [
        [
          {
            "node": "Trigger recursion of first level",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List all files in root": {
      "main": [
        [
          {
            "node": "Outputs new or updated files",
            "type": "main",
            "index": 0
          },
          {
            "node": "Wait for file comparison to complete",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Outputs new or updated files": {
      "main": [
        []
      ]
    },
    "Trigger recursion to next level": {
      "main": [
        [
          {
            "node": "Loop all subfolders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger recursion of first level": {
      "main": [
        [
          {
            "node": "List all files in root",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for file comparison to complete": {
      "main": [
        [
          {
            "node": "SetStartTime",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}