Filtering dataview results based on tags in the frontmatter and body of notes

New Obsidian user here. After months of feeling lost in the woods, I can see a strategy emerging that will greatly accelerate my workflow and it’s absolutely intoxicating (aside: whenever I get frustrated in such woods, I read this). Anyway, I feel like I have finally done enough research on my own to ask others to help!

What I’m trying to do

  1. Be able to show all notes that have a specific tag in the frontmatter (“tags” field) that is also in the frontmatter of the current note. [I use this approach for notes entirely related to that tag]
---
tags: project1
---
  1. Be able to show all bullets across all notes that have a specific tag appended to it [I use this approach for notes not entirely related to that tag such as daily notes]
- Remember this nugget #project1

Key to this… In both instances, I don’t want to have to specify the tag in my dataview code, because I’m applying the code via templates to many different notes. I want the code to reference whatever tags I have added to any file’s frontmatter.

Things I have tried

Thanks to this forum, I’ve pulled together dataview code that solves item #1 above.

TABLE summary
WHERE any(contains(file.frontmatter.tags, this.file.frontmatter.tags))

Great, but item #2 (the bullets query) is where I’m getting stumped.

I DO have working code that shows me all the bullets in any note that has a specific tag appended to it.

LIST WITHOUT ID item.text 
FLATTEN file.lists as item
WHERE contains(item.tags, "#project1")
SORT date DESC

This gives me the view I want, but as mentioned, I don’t want to have to hardcode the specific tag. So, I figured I would just add the WHERE condition from the Item #1 solution like this…

LIST WITHOUT ID item.text 
FLATTEN file.lists as item
WHERE any(contains(file.frontmatter.tags, this.file.frontmatter.tags))
SORT date DESC

That doesn’t work. It shows all bullets (whether I added the #project1 tag to them or not), and only from notes with a tag in the frontmatter matching the current file’s frontmatter, thereby ignoring all the other bullets out there that have the tag appended to it.

So, next I tried to replace the tag name in the working bullets query above with “this.file.frontmatter.tags”. So, like this…

LIST WITHOUT ID item.text 
FLATTEN file.lists as item
WHERE contains(item.tags, this.file.frontmatter.tags)
SORT date DESC

That doesn’t work either. (In fact, it spawns the dreaded everything-in-your-vault result, so I have to wait for 20 seconds while Obsidian renders the entire universe :face_with_spiral_eyes:)

Any help getting me to the finish line with this is greatly appreciated!

I do this in my vault quite a lot (and also “files that link to this file”, another useful dataview setup), but I’m away from my computer at the mo. But have found the solution in the forum for you, take a look at: Dataview: how to show notes that have tags in common with the current note?

1 Like

Thanks for taking a look @ShaneNZ ! No rush. Yes, in fact that is one of the posts I had found and reviewed before posting myself. I incorporated @mnvwvnm’s WHERE clause from that post in my code, but I added the “.frontmatter.” part because the query was finding tags elsewhere in the note.

However, that WHERE clause doesn’t work right in my bullets query as described in the code examples above.

This version brings back everything…

LIST WITHOUT ID item.text 
FLATTEN file.lists as item
WHERE any(contains(file.tags, this.file.tags))
SORT date DESC

… and this version brings back the wrong bullets…

LIST WITHOUT ID item.text 
FLATTEN file.lists as item
WHERE any(contains(file.frontmatter.tags, this.file.frontmatter.tags))
SORT date DESC

When doing combination of contains(list, list) I’m not trusting the otherwise excellent variable expansion of Dataview and like to map it myself.

For your first version on the file listings, I’d use something like the following

WHERE any( map(this.file.etags, (tag) => econtains(file.etags, tag) )

This will map each of the local tags, to a comparison against the candidate files. Then it use any( ... ) on that mapped list to check if any of them are matches. If you require them to match all tags, you’d use all( ... ) instead of the any( ... ) in the excerpt above.

For a file, there is a vital difference between file.tags and file.etags related to nested tags. The file.tags is expanded into each of the parts, so that if you define #my/nested/tag, it’s expanded into #my, #my/nested and #my/nested/tags. The file.etags is just #my/nested/tag.


However when it comes to items in lists, you’ve only got access to item.tags (and it behaves like the file.etags), so the corresponding expression to list out items would look like:

WHERE any( map(this.file.etags, (tag) => contains(item.tags, tag) ))

Finally, if this gets confusing, which I totally understand, doing queries like the one below could be helpful:

```dataview
TABLE file.tags, file.etags, any(mappedTags), all(mappedTags)
  
FROM "some folder"
FLATTEN list( map(this.file.etags, (tag) => contains(file.etags, tag))) as mappedTags
LIMIT 20
```

This would do the mapping without the filtering, and if you choose a folder where you have files which should/should not match, you’ll see the response of the various mapping and function calls. A good debug table is always a good thing to use in cases like these.

Updated: Corrected with an extra parenthesis

1 Like

Thanks @holroy. Great explanations of those concepts. Unfortunately, I won’t be able to work on this until later today, but will report back tonight. Thanks also for the debug table suggestion! I’d actually been wanting something like that. I’ve programmed with PHP in the past and would always print out the variables and arrays at certain points to see what was happening and wasn’t sure how to apply that in obsidian.

Thanks @holroy. Your WHERE clause solved my problem! (Note: I just had to add an extra closing “)” to the end.

Here’s the working code block that lists all bullets from any note when a bullet has been appended with a tag that is also included in the tags field of the current note’s frontmatter

LIST WITHOUT ID item.text 
FLATTEN file.lists as item
WHERE any(map(this.file.etags, (tag) => contains(item.tags, tag)))
SORT date DESC

My let’s-make-things-easy quest rolls on with momentum!

2 Likes

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