How can I use `default()` to add a tag only if note doesn't already have a sub-tag?

What I’m trying to do

Briefly, I want to update a dataview query so that notes that either have no tags at all or no kind/* tag appear to be tagged with kind/unknown.


I have a query that returns all notes related to a project, sorted/grouped by tag:

TABLE WITHOUT ID eTags AS "Kind", rows.file.link AS "Files"
FROM #Projects/ProjectNameHere OR "Projects/ProjectNameHere"
FLATTEN file.etags AS eTags 
WHERE contains(eTags, "#kind/") 
WHERE !contains(eTags, "#kind/project/index") 
GROUP BY eTags 
SORT Tags DESC

This works well; any note in Projects/ProjectNameHere OR tagged #Projects/ProjectNameHere shows up in the list AS LONG AS the file ALSO has a tag that begins with kind/.

I am trying to expand this to display notes that are either not tagged at all or notes that do not have a tag beginning with kind/

Things I have tried

Before even trying to complicate with conditionals, I figured that I would start with simply “injecting” a faux tag into any note that doesn’t have any tags via default() but this doesn’t seem to work:

TABLE WITHOUT ID eTags AS "Kind", rows.file.link AS "Files"
FROM #Projects/ProjectNameHere OR "Projects/ProjectNameHere"
WHERE default(file.etags, "#kind/unknown")
FLATTEN file.etags AS eTags 
WHERE contains(eTags, "#kind/") 
WHERE !contains(eTags, "#kind/project/index") 
GROUP BY eTags 
SORT Tags DESC

I created an empty note (Projects/ProjectNameHere/i-am-empty.md) with no content and thus no tags and I do not see that note in the rendered view.

Likewise, changing the type:

WHERE default(file.etags, ["#kind/unknown"])

Does not work, either.

I do not know how to inspect/debug the query so I have no clue if default() is doing anything.

Thoughts?

Initial thought is that maybe you should consider using a dedicated property, kind, to keep track of the type of object. Besides that, let’s see what we can do with your query. The requirements as I read them are:

  1. List notes with no tag at all ( not only not #kind/* )
  2. Ignore files tagged with #kind/project/index
  3. Any note having a #kind/* tag
  4. Notes with no #kind/*

This seems somewhat redundant… So here is an attempt, which you should be able to expand upon based upon my interpretation of your rules:

```dataview
TABLE rows.file.link as Files
FROM #Projects/ProjectNameHere OR "Projects/ProjectNameHere"

FLATTEN length(file.etags) > 0 as hasTags
FLATTEN any(map(file.etags, (etag) => startswith(etag, "#kind") )) as hasKindTags
WHERE !hasTags 
   AND ( hasTags AND !hasKindTags)
   AND hasKindTags

FLATTEN filter(file.etags, (e) => startswith(e, "#kind")) as onlyKindTags 
FLATTEN onlyKindTags as kTag
GROUP BY kTag as Kind
```

Basically this query should (as it is untested) return:

  • Any files having no tags, or files having tags but no #kind/* tags, or finally any file with any #kind/* tag
  • These files have their kind tag split, and we group the result by the kind tag

Hopefully this is in the ballpark of what you want, or gives you idea on how to set flags, combine them into meaningful combination at your end.

Thanks for getting back to me so quickly!

Initial thought is that maybe you should consider using a dedicated property, kind, to keep track of the type of object

Yeah, that’s one thing I considered but I decided early on that I wanted to keep the “kind” taxonomy usable via the tagging system.

The requirements as I read them are:

It was late after a long day when I drafted the post. New day, fresh eyes and the core of my ask is basically this:

(pseudo code, hopefully illustrates the algo I’m trying to re-create in dv query language)

uuid_of_interest = "Projects/ProjectNameHere"

all_relevant_notes = get_all_notes_in_dir(uuid_of_interest) + get_all_notes_with_tag(uuid_of_interest)

notes_by_kind = {}
for note in all_relevant_notes:
    if "kind/*" in note.tags:
      # Technically my notes can have multiple kind types. Not all do, but some can/do
      for _k in extract_kinds(note.tags):
          notes_by_kind[_k].append(note)
    else:
      notes_by_kind["unknown"].append(note)

for kind in notes_by_kind:
    print(f"{kind}"}
    for note in notes_by_kind[kind]:
        print(f"\t - {note.link}\n"}

Which would result in a list akin to:

- kind/work-log
    - workLog1
    - workLog2
    - workLog3
    - note4

- kind/meeting
    - meeting1
    - callNotes1

- kind/call
    - callNotes1

- kind/unknown
    - someHastilyCreatedNoteThatHasYetToBeTagged

Or said differently:

List all notes related to a project, subtract out $self; identifiable by #kind/project/index
If a note does not have a kind/* tag, pretend it has kind/unknown for the purposes of display/grouping
Display what’s left, grouped by their kind/* tag

Did you try my query?

Did you try my query?

Yes. It’s not working as expected.

With no changes:

Dataview: No results to show for table query.

Removing this stanza:

WHERE !hasTags 
   AND ( hasTags AND !hasKindTags)
   AND hasKindTags

Yields results that appear to be identical to the original query; Projects/ProjectNameHere/UntaggedNote.md does not show up in results.

The lack of inspection/debug-ability is incredibly frustrating.

If there’s a better way of pausing / inspecting what type(s) of data exist in a certain variable, i’d love to know about it.

As an attempt to inspect what onlyKindTags has, I added it as a column and removed the “deny all” filter stanza:

TABLE rows.file.link as Files, hasTags, onlyKindTags, kTag
FROM #Projects/ProjectNameHere OR "Projects/ProjectNameHere"


FLATTEN length(file.etags) > 0 as hasTags
FLATTEN any(map(file.etags, (etag) => startswith(etag, "#kind") )) as hasKindTags


FLATTEN filter(file.etags, (e) => startswith(e, "#kind")) as onlyKindTags 
FLATTEN onlyKindTags as kTag
GROUP BY kTag as Kind

Which produces results that are similar to the first: only things that feature a kind/* tag show up, and the onlyKindTags column has - for all rows (I guess that’s dataview for null?)

And same with the kTag/hasTags columns, too.