Dataview: Creating a table of all tags and the number of documents with that tag

What I’m trying to do

Create a table where all the tags in my vault are listed, except the ones in folders “folder 1” and “folder 2”. Along with that, I’d like to get the number of documents that have that tag.

Things I have tried

Frankly, I went through the documentation but couldn’t figure out how do I even query the number of docs with those tags.

Here’s a script I use to make a list. You can modify this to turn it into a table or make whatever other changes you need:

const fields = {}
  .forEach(x => {
    (x.tags || [])
      .forEach(y => fields[y.tag] = -~fields[y.tag])

dv.header(3, 'Tags')
  .sort((a, b) => fields[b] - fields[a])
  .map(x => `${x} (${fields[x]} notes)`))
1 Like

Sorry for sidetracking, but could you explain what this expression does, AlanG?

Update: It’s a not-easy-to-read way of adding 1. See operators - What does -~ do in JavaScript? - Stack Overflow

Good spotting! That’s my favourite part.

The ~ in Javascript is the bitwise NOT.

What is does is flip all the bits in a number, which essentially changes the sign from positive to negative and increasing the value by 1.

I use it here because it means you don’t have to initialise the output object with any values - you can flip the bit of undefined and make it -1. Then I negate the number which turns it into 1.

The next time it adds to that value, it turns the 1 into -2, which I negate back into 2.

Otherwise you’d have to go:

fields[y.tag] = fields[y.tag] ? fields[y.tag]+1 : 1

which sucks :stuck_out_tongue:

1 Like

I can like that feature/hack/…, and I have encountered the error of doing “undefined + 1” before, and had to rewrite my expression.

So I’m going to add this to my toolbelt (if I remember it the next time I encounter this). Just a little sad that it’s not intuitive what it does, and as such renders the code a little less readable (and understandable).

1 Like

This is great! Thanks! Sadly, I hate at JS :frowning_face: How do I modify this to exclude “folder 1” and “folder 2” though?

Never mind. I used ChatGPT and managed to get the code edited for my context. This works as intended, now :stuck_out_tongue_closed_eyes:

const EXCLUDED_FOLDERS = ["folder 1", "folder 2", "folder 3"];
const fields = {};

for (let [path, metadata] of app.vault.getMarkdownFiles().map(file => [file.path, app.metadataCache.getFileCache(file)])) {
  if (!EXCLUDED_FOLDERS.some(folder => path.startsWith(folder))) {
    (metadata.tags || []).forEach(tag => {
      fields[tag.tag] = (fields[tag.tag] || 0) + 1;

dv.header(3, 'Tags');
  .sort((a, b) => fields[b] - fields[a])
  .map(tag => `${tag} (${fields[tag]} notes)`));

1 Like

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