Query bulleted dates and/or tag under a specific header: advice

I have notes for different appliances (air conditioners, humidifiers, car, etc.) that have info on the purchase date, link to the pdf manuals, memos, and a maintenance log in each note. The maintenance logs are in this format in each note, usually with other text above and below:

### maintenance log

- 2022-12-28 - 水内部クリーン (初めて)
- 2023-01-27 - manually wiped filters and dust boxes.....
- 2023-02-28 - 水内部クリーン (14:22~18:25) #maint 

…and so on.

What I’m trying to do

Collect all maintenance tasks under the same header together in a table or list with or in context.

Things I have tried

  • Adding a #maint tag to the last date entry in each list and using Obsidian’s embedded search:
```query
tag #maint 
```

tag-query

Pros: Easy :smiley: Grabs any #maint tag.
Cons: Even with “Show more context”, I’d like a bit more. Have to manually move #maint to the last entry each time - not difficult but need to remember to move the tag.

  • Using regex to query for - NNNN-NN-NN
```query
path:  /^- (?:\d{4})-(?:\d{2})-(?:\d{2})
```

YYYYquery

Pros: Historical record for each note.
Cons: Picks up every date in a bullet; too many even if defining the path: to where the maintenance notes are. Will be ridiculous in a year or two. Order is random.


  • Decided to try Dataview (beginner :person_raising_hand:)
LIST file.lists.text
WHERE contains(file.etags, "#maint")

etags

Getting close to what I want…

  • Thinking it might help defining a FROM, I changed it to this which gives the same results as above but in a different order.
LIST file.lists.text
FROM #maint 

Pros: #maint only needs to be in a note once (in-line or YAML). Provides context and maintenance history at a glance.
Cons: Returns every bullet in the note, which is usually fine but, there are some outside of the ‘maintenance log’ heading that I don’t need or want to see.

  • I also tried changing a few of my bulleted dates to - [x] 2023-03-10 and using:
TASK
FROM #maint 
WHERE completed

…and it returns everything important, but isn’t separated out by appliance/note which I’d like to have.

Thanks for following along if you’re still here! So, my questions:

  • Specifically related to Dataview - is there a way to narrow down the results so only bullets under a specific heading that contain at least one #maint tag are listed?

  • More broadly, Dataview or not, can anyone see a different or more efficient way to query these notes to return only the bullets under the ‘maintenance log’ headers (tags or not)? Thanks for any input!

For my case,
I put #maint items as a TASK like the following.

- [ ] 🗓️2023-03-10 Wipe filters and dust boxes. [maint:: ac]
- [ ] 🗓️2023-03-11 Oxy clean. [maint:: humidifier]

With dataview

TASK
FROM ""
WHERE maint
GROUP BY maint

You might want to change “GROUP BY maint” with “GROUP BY file.name”.
And if you don’t want to see [maint:: humidifier] parts, you can enclose them with %% ~~~ %%.

I hope this helps.

1 Like

I’ve only used key:: value in playing around so far. Good opportunity to give it a try in my vault.

Thanks!

Since you’re using list items under headers already, it should be possible to use the section link, and manipulate that to only include those from given sections.

This’ll involve doing some magic with meta(), and possibly also FLATTEN. I can’t write it out just now, maybe later today in some hours. I’m on mobile just now, and a little busy.

Just wanted to let you know it’s doable, and also that we did something similar in another query within the last few months. So if you search for list and section and headers, you might find it…

1 Like

So the other reply I mentioned here was related to task, and not directly just list items:

(I also found a similar thingy by @mnvwvnm (which I’ve not seen for very long. Miss him), see Pulling tagged list items from particular file and showing their direct section heading? - #4 by mnvwvnm

So I found some time, and did some testing, and the “humidifier” test file looks like this:

---
type: appliance
---
### Maintenance log

- 2022-12-28 - 水内部クリーン (初めて)
- 2023-01-27 - manually wiped filters and dust boxes.....
- 2023-02-28 - 水内部クリーン (14:22~18:25) 

### Something else

- 2022-12-20 - Bought the humidifier
- 2023-01-25 - Wife complied about noise
- 2023-02-27 - It dripped on the floor...

Nothing fancy in there, besides another section, and a “type: appliance” field in the frontmatter. This is to limit the “global” search later on since we’re expands all list items into separate rows. So having some kind of limiter is better for performance. Could be a field like I’ve used, or a tag, or just that the appliances are within a given folder and then you’d use FROM in the queries below.

The evolution of the query

Just to let you in a little bit on how I’m thinking when developing something like this, it’s an evolution of the script starting from gathering all the needed data, more specific information, before fine tuning the queries for nicer display.

The entire test file (except for the final query) is shown below:

## All list items in all appliances

```dataview
LIST file.lists.text
WHERE type="appliance"
```

## All table query of items in all appliances

```dataview
TABLE item.text, item.section, meta(item.section)
FLATTEN file.lists as item
WHERE type="appliance"
```

## Limited to the Maintenance section

```dataview
TABLE item.section, item.text
FLATTEN file.lists as item
WHERE type="appliance"
  AND lower(meta(item.section).subpath) = "maintenance log"
```

With another humidifier in the 2nd floor, this produce the following output:

(Snipped some parts of the second table, and the last query gave: )

Hopefully, you’ll grasp my way forward, the real simplified explanation is:

  • Use FLATTEN file.lists as item to get access to each bullet point as a separate item
  • Use the meta(item.section) to get to the parts of the link, and to locate that we’re wanting to focus on the subpath part
  • Do a lower(...) just to lowercase the header, and make sure we don’t miss out if someone write “MAintenance Log” or similar
  • And then a little fiddling with the output

The final query I ended up with was:

```dataview
LIST rows.item.text
FLATTEN file.lists as item
WHERE type="appliance"
  AND lower(meta(item.section).subpath) = "maintenance log"
GROUP BY link(item.section, file.name) as myFile
SORT meta(myFile).display
```

Which produces this output for me:
image

(And might I point out that you got really good working on that humidifier in the second floor… :slight_smile: )

Also notice some extra trickery in that last query:

  • Using GROUP BY link(item.section, file.name), to create a new link directly to the relevant header, but using the actual filename as the display text.
  • Reusing the GROUP BY field to sort according to file name
  • Before I used GROUP BY I could list each item using just item.text, but since we’ve now grouped the query, we need to use `rows.item.text``

Hope this helps sorting out what type of maintenance you’ve down on your appliances, and also that you’ve learned something related to how to evolve your queries from a basic list to just the thing you want.

8 Likes

Very clever and interesting solution. It does only pull the bullets under ### maintenance log! Success!

I had a look at the Dataview documentation - meta() is mentioned briefly but is slim on examples - you should submit this one for the Dataview documentation! I could see this query being useful for a lot of folks. So much to learn.

And yes, the humidifiers were well cared for, no complaints, and served us well the past few dry months, but will soon take a rest and pass the baton on to the new fancy “AI” air conditioner for all dehumidification and cooling needs. :beach_umbrella:

Thanks again for your time and insight.

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