Advanced Logseq queries can be useful
Logseq has a nifty feature where if you use their time tracking primitives it’ll automatically use a query under the hood to show you the tasks that you’re currently working on (ie blocks that begin with NOW
). I vaguely knew that under the hood it was using a Logseq advanced query, but hadn’t previously looked into how they actually worked, so today I decided to rectify that.
I learned some interesting things while investigating this:
-
Every graph has a
logseq/config.edn
in it’s top-level folder -
this
config.edn
file contains has a key called:default-queries
which is what made the NOW feature work: it’s just a query that runs when you’re on a daily journal page
Here’s what the default queries look like in a freshly created Logseq graph:
:default-queries
{:journals
[{:title "🔨 NOW"
:query [:find (pull ?h [*])
:in $ ?start ?today
:where
[?h :block/marker ?marker]
[(contains? #{"NOW" "DOING"} ?marker)]
[?h :block/page ?p]
[?p :block/journal? true]
[?p :block/journal-day ?d]
[(>= ?d ?start)]
[(<= ?d ?today)]]
:inputs [:14d :today]
:result-transform (fn [result]
(sort-by (fn [h]
(get h :block/priority "Z")) result))
:collapsed? false}
{:title "📅 NEXT"
:query [:find (pull ?h [*])
:in $ ?start ?next
:where
[?h :block/marker ?marker]
[(contains? #{"NOW" "LATER" "TODO"} ?marker)]
[?h :block/page ?p]
[?p :block/journal? true]
[?p :block/journal-day ?d]
[(> ?d ?start)]
[(< ?d ?next)]]
:inputs [:today :7d-after]
:collapsed? false}]}
These queries are using Datalog (a query language that’s popular with the clojure community). Unfortunately Logseq’s documentation on using them effectively is a little scattered (though this, and this got me pointed in the right direction) and didn’t walk through the basics.
I wanted to set up a query that would let me all the tasks I’d completed in the last 7 days. So with some squinting and a little help from my friendly neighborhood LLM I managed to come up with this query which looked right:
{:title "✅ DONE (Last 7 Days)"
:query [:find (pull ?h [*])
:in $ ?start ?today
:where
[?h :block/marker "DONE"]
[?h :block/page ?p]
[?p :block/journal? true]
[?p :block/journal-day ?d]
[(>= ?d ?start)]
[(<= ?d ?today)]]
:inputs [:7d :today]
:collapsed? false}
Thing is, I didn’t want this query to show on all journal pages the way the default queries do, I wanted to have it live in it’s own page that I could go look at on-demand.
This was harder than it should’ve been to glean from the docs, but turns out to start a query you need to create a block (not a fenced code block, just a normal block) and put #+BEGIN_QUERY
and #+END_QUERY
at the end of it, and then put your query in the middle of it, after which Logseq will automagically render the query results similar to how the built-in NOW query that got me started on this whole thing works.