I want to have a line of text somewhere which will say:
Internal links across the vault: $m$ placeholders / $n$ total
It is a must that this line will be updated automatically. It will be elating to have such stats per-note, right at the “outgoing links” linked view.
Is there any way, doesn’t matter which one, to achieve that? I don’t care where exactly it will be rendered, in the statusbar, on the special (auto-updated) note, in the settings UI, just want these numbers to be visible.
Things I have tried
I know Dataview plugin exists but don’t know the exact capabilities and/or API so don’t know whether it’s possible to dig this info out of the vault index.
I have found the Vault Full Statistics plugin which is already pretty nice, but it shows only the total amount of links, it doesn’t show the amount of placeholder links.
So basically the count of all files having no in- or out-links in them versus the total number of files.
Try the following queries in a note of its own:
## Count of files with a given set of links
```dataview
TABLE fileCount
GROUP BY length(file.inlinks) + length(file.outlinks) as AllLinkCount
FLATTEN length(rows) as fileCount
```
## Count of file with no or some links
```dataview
TABLE sum(rows.fileCount) as "Number of files"
GROUP BY length(file.inlinks) + length(file.outlinks) as AllLinkCount
FLATTEN length(rows) as fileCount
GROUP BY choice(key = 0, "No links", "Some links") as hasNoLinks
```
Total number of files: `$= dv.pages().length `
Which should equate to 1262 grey nodes, and 803 no-grey nodes, where the total number of files in my test vault is 2065. I reckon you don’t really need the first query, it’s just there to hopefully help you understand what I do in the queries.
The gist is simply to keep the number of links in and out of any file, and then group together the files having that number of links. Those having 0 links will be the nodes with no links in the graph view.
( PS! This doesn’t account for tags being nodes, it’s just the file nodes)
Do I understand correctly that simply by doing [[Name of the note to be created sometime later]] I’m creating a “file” as far as Dataview plugin is concerned?
Also, I don’t really think that counting the “files which have no in-links pointing to them” is the query I need. The whole point of the “placeholder link” concept as far as I understand is that I create a reference to a note which doesn’t exist yet - the link is there but the note is not.
For the completeness’s sake, here is what I actually wanted to do.
The raw Object.keys(dv.app.metadataCache.unresolvedLinks).length gives a different number which is useless for me. It gives the amount of pages which contain the “unresolved links” this is not what I want. I want the length of the list of these links!
The following is the code which aggregates this number from the raw data from Dataview API, and solves my problem completely:
Pages in vault: 969 unresolved / 391 existing / 1360 total
Which is all I wanted.
Of course we can do a lot of interesting things inside the final forEach where we have the full context. For example, we can build a Wikipedia-style list of “most wanted pages”.
do not blindly put this code into your vault it is seriously slow to render
like mere 900+ lines in the list will render for seconds and rendering it as a table hangs the UI for around a minute.
// Native JS object to accumulate the counts for each name
const counts = {};
Object.entries(dv.app.metadataCache.unresolvedLinks)
.forEach(
([page, links]) =>
Object.entries(links).forEach(
([name, amount]) => {
// clever tricks to increase a possibly null or undefined value on a single line
counts[name] = (counts[name] ?? 0) + amount;
}
)
)
// we used a native JS object to deduplicate the names
// to render in table/list we need an array of pairs (name, count)
// `Object.entries` gives us exactly that
const countsArray = Object.entries(counts);
// two-level sort: by count decreasing, by name alphabetical
countsArray.sort(
(left, right) => {
const diff = right[1] - left[1];
if (diff === 0) {
return left[0].localeCompare(right[0]);
} else {
return diff;
}
}
);
dv.header(2, 'Most wanted pages');
// table is ultra slow so use at your own risk
// dv.table(['link', 'count'], countsArray.map(([link, count]) => [`[[${link}]]`, count]));
dv.list(
countsArray
.map(
// render names as links to be able to immediately create these pages
// render the count only if larger than 1
([link, count]) => `[[${link}]]` + (count > 1 ? ` (${count})` : '')
)
)