Markdown Table Subselectors

March 5th, 2023

For a while, I’ve struggled with notes. Notion has the bells and whistles, but I prefer the portability and simplicity of plain text files. That’s why Obsidian clicks for me. Instead of a proprietary format, it enriches plain text, specifically markdown.

I love markdown. It prioritizes writing above formatting. But markdown’s clunkiest feature is tables. Obsidian’s advanced tables plugin changed this. It makes tables more effortless without making them spreadsheets. Markdown tables should be about formatting structured data, not replacing the computation or aggregation you find in spreadsheets or databases.

I wanted a syntax for selecting rows and columns from tables that stayed true to markdown’s core of prioritizing simplicity over complexity.1 No aggregating or windowing; only selecting rows and columns. In SQL terms, only SELECT, FROM, WHERE, ORDER BY, and LIMIT. This limitation is necessary because Markdown tables have no schema.

I call this syntax “table subselectors” or tss for short. Its syntax borrows from markdown image embeds and css attribute selectors.

Expression Explanation
!\| resource \| Embed a table or csv
!\| resource\#header \| Finds the first table after header
!\| resource[col=val] \| Filter by column value
!\| resource[col=val,val2] \| Filter by multiple values
!\| resource[col=val][col2<=val] \| Filter by multiple columns
!\| resource[col=val],[col<>val] \| OR filter
!\| resource { col; col2} \| Column selector (default includes all)
!\| resource { alias: col1 + col2 } \| Column aliasing, simple expressions
!\| resource { col1, ... } \| Spread syntax for “remaining” columns
!\| resource { alias: col1 + col2 } \| Column aliasing, simple expressions
!\| resource>col1<col2 \| Sort by asc or desc
!\| resource:n \| Limit rows by n
!\| resource:m-n \| Select rows m through n
!\| resource[col=?] \| Parameterizable filter


Say you have a directory with files

some text

# hi

explanation of table...

| col1 | col2 |
| ---- | ---- |
| foo  | bar  |
| baz  | qux  |

!|[col1=foo] { col2 }| would render as:

| col1 |
| ---- |
| bar  |

Or, in the more complicated example of tss:

!|source.css#populations[continent=Asia,Europe],[population<1000000000]>population:3 { Location: country + ', ' + continent, ...}|

This selects the top three countries in Asia or Europe by population, excluding countries with a population of more than 100m. tss probably starts to become clunky around 100 characters but you figure most tss expressions will be shorter than that, like “give me the top 3 countries by population in Asia and Europe: !|source.css#populations[continent=Asia,Europe]>population:3 { country; population }|.

The only other item on my wishlist would be a CSV editor plugin that behaves like Obsidian’s advanced tables than the current plugin. Instead of creating a tablular editor, you should align commas for formatting and support keyboard shortcuts like tabbing, returning, and arrow keys. Other functions, like manipulating rows or columns, should be supported via the menu. That, combined with tss supporting csv’s and other tabular formats, would be the near perfect tool for integrating data into the markdown toolchain.

What’s next

I need to acquire a bit more experience with CodeMirror before trying these crazy ideas out, but I wanted to inscribe them on the proverbial stone tablet, in case they’re useful.

  1. I looked into the Dataview plugin, but for me, it has too much power and complexity for me. It’s also a meta tool, querying the structure of Obsidian itself.