Ooooh recursion, how fun! (Recursion is one of the tougher topics in many computer science or programming courses but you have an excellent example right here for thinking through the concepts, thank you for sharing!)
I don’t know how to do this in the dataview query language (DQL) but if you’re willing to try Javascript there’s an example very similar to what you are looking for on the codeblock examples page in the documentation. That example is looking at incoming links as well as outgoing, though, so you’ll want to modify it a bit. That’s what the rest of this post is about. You also might consider looking at additional community plugins such as “Breadcrumbs” or things under the search term “MOC” in the plugin search to see if any will just do what you want!
Commented code from the example, which searches incoming links
This would go in a dataviewjs codeblock instead of the dataview one you are currently using. You might need to enable javascript queries in your dataview settings. The symbols /*
and */
start and end a comment, respectively, in Javascript, so you can delete or write anything inside them without changing the functionality of the code. Some of the comments below were written by the author of the dataview documentation and some by me.
let page = dv.current().file.path;
let pages = new Set();
let stack = [page]; /* everything to do with stack is the bit I have no idea how to do in regular DQL */
while (stack.length > 0) {
let elem = stack.pop();
let meta = dv.page(elem);
if (!meta) continue; /* ignore links to pages that don't exist yet */
for (let inlink of meta.file.inlinks.concat(meta.file.outlinks).array()) {
/*console.log(inlink);*/
if (pages.has(inlink.path)) continue; /* only look at pages we haven't seen yet, otherwise we could get stuck following circular links forever */
pages.add(inlink.path);
stack.push(inlink.path);
}
}
/* Data is now the file metadata for every page that directly OR indirectly links TO the current page. */
let data = dv.array(Array.from(pages)).map(p => dv.page(p));
/* Display the table. The part with quotes is a list - indicated by the single [ ] around it, which mean list or array in JS - of your column names, like if you used AS in a dataview query, so change them however you like.
The part after "(p =>" is a list of the stuff you want in your columns.
I tried to match what I think your TABLE example from your post would do. */
dv.table(["File Link", "file.name"], data.map(p => [p.file.link, p.file.name]));
Modifying the example
You want to know about outgoing links (aka “outlinks”) not incoming links.
So we want to change the part of the code that starts with for
.
for (let linkedFile of meta.file.outlinks.array()) {
/*console.log(linkedFile);*/
if (pages.has(linkedFile.path)) continue; /* only look at pages we haven't seen yet, otherwise we could get stuck following circular links forever */
pages.add(linkedFile.path);
stack.push(linkedFile.path);
}
I recommend hand modifying your lines of code rather than copy-pasting this in so that you know it’s still in the right place with respect to the }
at the end of the while loop.
Does this work for you?
Good luck, please let me know if I can clarify anything! This was a lot of code for a short question.