Jomi
September 4, 2025, 6:51am
1
I am trying something again, after checking many posts. Nobody seems to be able to solve it.
In the journal I enter this:
Meeting 1 #customer1
text
TODO action 1
TODO action 2
Meeting 2 #customer2
text
TODO action 3
TODO action 4
Meeting 3
Then I want to make a query in the journal template which shows all tasks, grouped by the block header tag. If no tag exists, then all the other tasks can be grouped together. This should result in the output:
#customer1
TODO action 1
TODO action 2
#customer 2
TODO action 3
TODO action 4
TODO action 5
In many task-apps this is standard behavior. In Logseq entering all in the Journal is great, but sorting the output you want with many tasks per block header tag.
Currently I use this query, which doesn’t group the tasks per block header tag and doesn’t display the tag:
#+BEGIN_QUERY
{:title "🔨 NOW, TODO or DOING"
:query [:find (pull ?h [*])
:in $ ?start ?today
:where
[?h :block/marker ?marker]
[(contains? #{"NOW" "TODO" "DOING"} ?marker)]
[?h :block/page ?p]
[?p :block/journal? true]
[?p :block/journal-day ?d]
[(>= ?d ?start)]
[(<= ?d ?today)]]
:inputs [:9999d :yesterday]
:result-transform (fn [result]
(sort-by (fn [h]
(get h :block/priority "Z")) result))
:group-by-page? true
:breadcrumb-show? true
:collapsed? false}
#+END_QUERY
Has anyone solved this? I am convinced that it must be possible.
3 Likes
Try this:
#+BEGIN_QUERY
{
:title "Todos grouped by customer"
:query [:find (pull ?b [*])
:where
[?b :block/marker ?m]
[(= ?m "TODO")]]
:group-by-page? false
:result-transform
(fn [result]
(let [by-tag (group-by
(fn [b]
(let [tags (:block/tags b)]
(if (seq tags)
(clojure.string/join ", " tags)
"No Tag")))
result)]
(for [[tag blocks] by-tag]
[:div
[:h3 tag]
(for [b blocks]
[:div (first (:block/content b))])])))
}
#+END_QUERY
Jomi
September 4, 2025, 12:04pm
3
Thanks for this. Unfortunately the query gives an error (Logseq version 0.10.13). Can you try again?
Could you list the most relevant ones?
What makes you so sure?
It most probably isn’t possible.
At least not with queries alone.
Workarounds could still be possible.
e.g. sorting instead of grouping
It would help if you were specific about the given error.
I formatted the query to avoid errors on copying.
It will probably not produce the desired results anyway.
It looks like the output of an LLM.
Jomi
September 8, 2025, 8:23am
5
mentaloid:
Logseq tags and namespaces are fundamental to Logseq. When logging notes about projects in the Journal and tagging with namespace tags, it must be possible to provide and overview grouped by name-space.
mentaloid:
Workarounds could still be possible.
e.g. sorting instead of grouping
Ιndeed this might work.
mentaloid:
It would help if you were specific about the given error.
This is the output of the query of @menkizar
I hope with this background and additional information, there is someone who can build this formula or already did and is using it. With this, the task management of Logseq again is more complete, closing the gap with more task specialized PKM’s.
1 Like
Jomi:
mentaloid:
Workarounds could still be possible.
e.g. sorting instead of grouping
Ιndeed this might work.
Try updating your query with the following steps:
Replace all (3) ?h with ?b.
This is because of an issue with the source code.
Add these conditions to get the customer name from the parent-block:[?b :block/parent ?parent]
(or-join [?parent ?ref-name]
(and
[?parent :block/refs ?ref]
[?ref :block/name ?ref-name]
)
(and
(not [?parent :block/refs ?ref])
[(str "none") ?ref-name]
)
)
Replace "none" with whatever you want to print when no tag exists.
Output the customer name by replacing :query line with this::query [:find ?ref-name ?marker (pull ?b [*])
:keys ref status b
Extract the output and sort it by customer, by replacing :result-transform lines with this::result-transform (fn [result]
(map (fn [r]
(update (:b r) :block/properties (fn [p]
(assoc p "status" (:status r) "ref" (:ref r) )
) )
) (sort-by :ref result))
)
Switch the query to table view.
Jomi
September 9, 2025, 7:41am
7
Many thanks for this, which resulted in this query:
#+BEGIN_QUERY
{:title "🔨 NOW, TODO or DOING"
:query [:find ?ref-name ?marker (pull ?b [*])
:keys ref status b
:in $ ?start ?today
:where
[?b :block/marker ?marker]
[(contains? #{"NOW" "TODO" "DOING"} ?marker)]
[?b :block/page ?p]
[?p :block/journal? true]
[?p :block/journal-day ?d]
[(>= ?d ?start)]
[(<= ?d ?today)]
[?b :block/parent ?parent]
(or-join [?parent ?ref-name]
(and
[?parent :block/refs ?ref]
[?ref :block/name ?ref-name])
(and
(not [?parent :block/refs ?ref])
[(str "none") ?ref-name]))]
:inputs [:9999d :yesterday]
:result-transform (fn [result]
(map (fn [r]
(update (:b r) :block/properties (fn [p]
(assoc p "status" (:status r) "ref" (:ref r)))))
(sort-by :ref result)))
:view :table
:breadcrumb-show? true
:collapsed? false}
#+END_QUERY
It shows again the tasks but is not yet fully working. There are 2 issues:
I have tasks TEST under namespace Project/meeting1, the result of this query is that it shows TEST 2x in the results. Once for Project and once for Project/meeting1.
I created a task in Project/meeting1 under another block (indent), after which it looses the ref to the namespace.
I hope with this feedback, the query can be fixed?
Need to provide exact examples, like in your opening post. Could also use a separate temporary graph, to further simplify testing.
Jomi
September 9, 2025, 9:23am
9
You are right. Here is the example input and query output:
Input:
All input via the current Journal page:
Journal-date Sept 9th, 2025
Meeting with Peter #Project1 /subprojectA
Meeting notes
WAITING task XYZ for Peter
Other Important actions (more indented)
TODO task XYZ for Jim
TODO task XYZ for Abel
General actions #Project1
Information
TODO general tasks to not forget
Meeting with Alice #Project2 /subprojectA/kickoff
Meeting notes
TODO task XYZ for Alice
Output in table format, combining open tasks and name-spaces
PROJECT OPEN TASKS:
Status
Block/Description
Page/Created
Ref/Project tag
WAITING
task XYZ for Peter
Sept 9th, 2025
Project1/subprojectA
TODO
ask XYZ for Jim
Sept 9th, 2025
Project1/subprojectA
TODO
ask XYZ for Abel
Sept 9th, 2025
Project1/subprojectA
TODO
general tasks to not forget
Sept 9th, 2025
Project1
TODO
task XYZ for Alice
Sept 9th, 2025
Project2/subprojectA/kickoff
Key points:
ideally you can also sort on every header in the table, most important on Project Tag.
with many projects, this overview continues to look okay
ideally you can also change TODO to DONE in the table view
tasks inherit the last name-space tag of the block, which is made visible in the table
Hopefully this clarifies the purpose, input and output enough to build the query for this. I think the last query is already very close.
Don’t get carried away with the requirements. This remains a mere workaround.
Add these rules::rules [
[(first-valid-ref-name ?b ?ref-name)
[?b :block/refs ?ref]
(not
[?sub :block/namespace ?ref]
[?b :block/refs ?sub]
)
[?ref :block/name ?ref-name]
]
[(first-valid-ref-name ?b ?ref-name)
(not [?b :block/refs])
[?b :block/parent ?parent]
[?parent :block/page]
(first-valid-ref-name ?parent ?ref-name)
]
]
The presence of :rules requires to alter line :in like this: :in $ ?start ?today %
Use the rules in or-join like this:(or-join [?parent ?ref-name]
(first-valid-ref-name ?parent ?ref-name)
(and
(not (first-valid-ref-name ?parent ?ref-name))
[(str "none") ?ref-name]
)
)