Dataviewjs How to count number of untagged pages?

I have the following that provides a list of all the pages in my vault that have not been tagged:

Table From "" 
WHERE length(file.tags) = 0 
SORT file.mtime desc 

The count generated by the above is a 174 files.

The reason I’m interested in this is that I am treating untagged notes as notes that I have not yet processed. I want to keep this figure as low as I can so would like to track it on my dashboard on my Home page which has the following items:

-  File Count: `$=dv.pages().length`
-  Library Books: `$= dv.pages('"Sources/My_Library"').length`
-  Books Read: `$= dv.pages('"Sources/My_Library"').where(p => p.status == "read").length`
-  Cards/Concepts: `$=dv.pages('"Cards"').length`

Therefore, I would like to add a row that has ‘Untagged Notes:’ and for it to return the figure of 174 as the dataview script above currently does.

I hope that makes sense - thank you.

This was actually more tricky than expected. Part of this is due to how different references will handle the tags and the length of that tag.

Using the tag #my/somewhat/long/nested/tag as an example:

  • file.etags.length will return 1
  • file.tags.length will return 5:
    • #my/somewhat/long/nested/tag
    • #my/somewhat/long/nested
    • #my/somewhat/long
    • #my/somewhat
    • #my
  • tags.length will return 27, since that is the length of the text

So, the most precise count of tags you can get is to do:

Untagged: `$= dv.pages().where(p => p.file.etags.length == 0).length `

The only caveat with that count, is that it does include illegal tags, if you have any of those in your vault.

I did some local testing, with this as the result:

The column headers indicate what’s used, where feTags stands for file.etags, f# stand for file.tags.length, and tagsType is typeof(tags). Hopefully that make sense, if not see the script below for the actual code used.

Some key facts to read out of the image:

  • Both file.etags and file.tags are always of the type object(aka arrays in our case). The tags type varies, and doesn’t read list item tags at all
  • The count of file.etags and file.tags seems reliable, when you take into account how file.tags splits the nested tags
  • Neither method has a good detection of illegal tags, or presence or not of the tags: field.
  • Repetions of tags doesn’t count
  • Not shown, but it doesn’t matter whether the tags are defined in the frontmatter or the body text
Dataviewjs script to generate this image
const values = dv.pages()
  .where(p => p.file.folder == dv.current().file.folder)
  .map(p => 
  [, p.file.etags, p.file.etags?.length, typeof(p.file.etags), "||", p.file.tags, p.file.tags?.length, typeof(p.file.tags), "||", p.tags, p.tags?.length, typeof(p.tags)])
dv.table(["file", "feTags", "fe#", "feType", "", "fTags", "ft#", "ftType", "", "Tags", "#", "type"], values)

Theoretically you could run that on an entire vault, but I would recommend against it. If you’re inclined to look at similar stuff in your vault, please run the script below.

A slightly simpler tag viewing script
const values = dv.pages()
  .where(p => p.file.etags?.length > 0)
  .map(p => 
  [, p.file.etags, p.file.etags?.length, "||", p.file.tags, p.file.tags?.length, "||", p.tags, p.tags?.length, typeof(p.tags)])
dv.table(["file", "feTags", "fe#", "", "fTags", "ft#", "", "Tags", "#", "type"], values)

To make this script not so intrusive, I’ve done the following alterations:

  • Removed the folder limitation I used, so it read the entire vault
  • Add a limit(100) to show only the 100 first. Change this if you dare to…
  • Removed the type for file.etags and file.tags since they’re always of the object type
  • Removed any entries where file.etags.length is zero, so that you can focus on seeing how the numbers differs when using the different variants

Hi Holroy, Many thanks for both the swift and detailed response. This sounds like this provided you with an interesting challenge and I am pleased to say that this has given me exactly what I wanted for my home page. Many Thanks again for taking the time to look at this.

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