How can I run down all nodes and pull out all data for matching name?

Describe the problem/error/question

Hi, first post so go easy :slight_smile: I have been using n8n and loving it but cant workout how to pull all the nodes from a JSON request. I have tried searching the forum and found lots of other help but nothing on this.

I am trying to take a Google Slides file (although the question is generic), find all nodes that match a specific type and return them. Example:

—PageId: 12
----Content: TEST123
----Content: TEST321
— Shape
—PageId: 123
—PageId: 1234
----Content: TEST11

I would like get a response with the PageId any any content whenever it exists. In the above it would

PageId: 12,Content: TEST123
PageId: 12,Content: TEST321
PageId: 1234,Content: TEST11

I know i can pull the first one by using direct links in the expression:

e.g. {{ $json.Root[0].Page[0].Text[0].content }}

The real names are: “content” and “objectId”



So i guess the real question is can I change the array locations to be “all” instead of a number?

Please share your workflow

Share the output returned by the last node

Output from the node is very large so its on justpaste:

Information on your n8n setup

  • n8n version: Cloud

It looks like your topic is missing some important information. Could you provide the following if applicable.

  • n8n version:
  • Database (default: SQLite):
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via (Docker, npm, n8n cloud, desktop app):
  • Operating system:

Hi @James_Hiscott, welcome to the community!

I am not super familiar with the Google Slides data structure, but using a very simple test document the following workflow did the job for me:

Instead of the Item Lists node I am using a JMESPath expression to only return the page number and the actual text values:

It might need a little more tweaking in case some fields are not available in your document, but I hope the basic idea still works for you :slight_smile:

1 Like

Thank you so much @MutedJam it works perfectly. If you have time would you mind explaining how the jmespath works so next time I can work it out :slight_smile:

My understanding is this:
jmespath takes an object and a search sting. In the example you are passing in the pageElements as the object but i get fuzzy on how the search part is working.

Does the [] mean any array number? e.g. [0],[1],[2] and so on? as a result it finds all the .shape items?

That makes sense, but i am not sure how the | [?text] part work?

{{ $json.pageElements ? $jmespath($json.pageElements, "[].shape | [?text].text.textElements[].textRun.content") : [] }}

Thanks again for your solution.

1 Like

Glad to hear this works!

would you mind explaining how the jmespath works

Tbh, I am really not great at JMESPath. I usually play around until I get something useful. But let’s try :D. When reading the below keep in mind that n8n uses a slightly different syntax than the original JMESPath libraries as explained in our documentation (this is relevant when looking at examples in the JMESPath documentation itself).

First, not all of the expression is JMESPath actually. The $json.pageElements ? ... : ... part is a JS shorthand for if/else (the ternary operator, explained here for example). This essentially checks whether a pageElements field is present. If so, the “true” part left of the colon : is used, if not the “false” part right of the colon is used instead. I added this to account for slides without any content.

The actual JMESPart part is this:

$jmespath($json.pageElements, "[].shape | [?text].text.textElements[].textRun.content"

To get an idea of what this does I suggest starting with opening the larger expression editor/preview using this little “pop out” icon:


Start with an expression of just $jmespath($json.pageElements, "[].shape"). This gives us a new array consisting of just the shape items just as you suspected:

Then add | [?text]. The | character tells JSON that another expression follows (pipe), with [?text] then filtering out all objects that do not have a text field.

Next I’ve appended .text.textElements[]. This returns an array consisting of all the textElements[] values inside the text field (this is when I realized the actual text is nested even further down the data structure :see_no_evil:):

This is a great data structure to work with since we have an array consisting of only objects (and not more nested arrays like we had before). So all that’s left is adding the path to the actual content which is .textRun.content:

tl;dr my approach to getting JMESPath right is going step by step with lots of trial and error along the way especially the pipe or not part (do I need a | or not I get often wrong).

Hope this still makes sense and helps a little bit :slight_smile: