Find all non-existant notes and the note they're mentioned in

Hi all,

I’ve got this nice dataviewjs query which shows me a list of all non-existant notes:

let r = Object.entries(dv.app.metadataCache.unresolvedLinks) 
	.filter(([k,v])=>Object.keys(v).length) 
	.flatMap(([k,v]) => Object.keys(v)
	.map(x=>dv.fileLink(x)))  
dv.list([...new Set(r)])  

The only downside of this query is that I don’t see where the non-existant note is mentioned. Are there any JS-guru’s here that can help me extend this query to a table where the original note is linked?

Thanks a million in advance!

Your query looses the original connection through the way you’re flattening the unresolved links, so how do you want your output to be?

Do you want the unresolved file to be in the leftmost column (as a link?), with all the origin files (as links?) in the rightmost column? Or do you want the origin files at the left, will all its unresolved files at the left?

A taster for the easy solution, with origin at left (as links), and unresolved at right (not as links):
image

Unfinished script which produced the above image
```dataviewjs
const unresolvedLinks = Object.entries(dv.app.metadataCache.unresolvedLinks)
      .filter(([origin, unresolved]) =>
              Object.keys(unresolved).length)

console.log(unresolvedLinks)
dv.table(["Origin file", "Unresolved"],
         dv.array(unresolvedLinks)
           .map(item =>
                [dv.fileLink(item[0]),
                 Object.keys(item[1])]))
```

Here is another version which produces lots of links to both the unresolved files for creation purposes, and to the origins for cleanup purposes.

image

```dataviewjs
const basedata = Object.entries(dv.app.metadataCache.unresolvedLinks)
      .filter(([origin, unresolved]) =>
              Object.keys(unresolved).length)

// Build dictionary (or set) with key on the new file
let unresolvedDict = {}
for (let [origin, unresolvedList] of basedata) {
   for (let newFile in unresolvedList) {
      // If first time we see this, create an array...
      if (!unresolvedDict[newFile]) 
        unresolvedDict[newFile] =  []

      // Push another origin into the array
      unresolvedDict[newFile].push(dv.fileLink(origin))
   }
}

dv.table(["Unresolved", "Origin(s)"],
   Object.entries(unresolvedDict)
   .sort((a, b) => (a[0].toLowerCase() < b[0].toLowerCase() ? -1 : 1))
   .map(item => [dv.fileLink(item[0]), item[1]])
  )
```

Hope this helps!

@holroy gives you the right solution (I have difficulty understanding some parts of the code - as a js dumb -, but the results show it).

My contribution here is related with the DQL side.

We can achieve some good results with regular queries. But the results accuracy depends in the way you organize some “real” files.

An example: if you don’t place in the root path your non-markdown files (images, pdf, etc) linked in your md files, then you can use a query like this

TABLE rows.OUT AS Unresolved
FLATTEN file.outlinks AS OUT
WHERE !OUT.file AND !(contains(meta(OUT).path, "/"))
GROUP BY file.link AS Source

If you don’t use dots (.) in the folders and file names, then you can use something like

TABLE rows.OUT AS Unresolved
FLATTEN file.outlinks AS OUT
WHERE !OUT.file AND !(contains(meta(OUT).path, "."))
GROUP BY file.link AS Source

I repeat: these are a tricky ways to achieve the wanted goal in dql side. But the js approach via app.metadataCache.unresolvedLinks is the right way.

1 Like

Wonderfull ! Marvelous ! Thank you SO MUCH ! :pray:
I’ve been using the plugin “Find orphaned files and broken links” for ages. This is so much better and more usefull !

By the way : could you eventually produce a script that makes a table of the unlinked (ie. orphaned) files ? A dataview table is so convenient, especially because it doesn’t “pollute” the graph view.

Olivier :-{)

By orphaned file you mean files without backlinks?
If yes, you can try something simple like:

LIST 
FROM "your-folder-path"
WHERE !file.inlinks
  • adapt FROM "your-folder-path" for your real folder path or, if for all vault, remove all the expression)

  • why a table? you want to see other fields/relations?

Thank you very much.
Yes, I’d like a table of all the files without backlinks, with a column telling the folder they’re residing in.
(I have bursts of creativity during which I produce a certain number of “seed” cards. They are easily forgotten…)

TABLE file.folder AS Folder
WHERE !file.inlinks

Thank you very much !

Ah, the power of the “object notation” — if my understanding is correct — is incredible. Could you maybe point me towards some tutorial ? If I could deepen my understanding without taking a college course in programming, I would definitely do it. It looks like I could do so much more in automation…

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.