Queries for task management

Thanks! Things are working, I’m exploring other functionalities now. I understand the structure better.

1 Like

I was going to come back to this point and say, sorry I haven’t managed, but then I had a random bout of inspiration…

I’m not going to say it is flawless and probably it requires better testing, so here’s me saying, try it!

#+BEGIN_QUERY
{:title [:h3 "⚡️ Lopend"]
 :query [:find ?project (count ?b) (sum ?count) ;count ?b is required to show the correct sum of ?count
   :keys project block taken ;define keys to use in the view below
   :where
     [?t :block/name "taskcount"] ;page named taskcount
     [?p :block/tags ?t] ;get all pages tagged with taskcount
     [?p :block/journal? false] ;that aren't journals
     [?p :block/original-name ?project] ;put the original page name in variable ?project
     [?b :block/page ?p] ;get blocks on the found pages
     ;Anything above this line can be edited to fit what you need to find in terms of a project name and related tasks!
     (or
       (and
         [?b :block/marker "TODO"] ;block is a task
         [(* 1 1) ?count] ;set count to 1
       )
       (and
         (not [?b :block/marker "TODO"]) ;block is not a task
         [(* 0 1) ?count] ;set count to zero
       )
     )
 ]
 ;Use of :view to display our result in a table
 :view (fn [rows] [:table 
   [:thead [:tr [:th "Project"] [:th "Tasks"] ] ]
   [:tbody (for [r rows] [:tr 
     [:td [:a {:href (str "#/page/" (clojure.string/replace (get-in r [:project]) "/" "%2F"))} (get-in r [:project])] ]
     [:td (get-in r [:taken]) ]
   ])]
 ])
}
#+END_QUERY

Let me know how it works out. Or if you need any help adjusting the query for your needs.

2 Likes

Here’s another question for you, @Siferiax :slight_smile:

I’ve got a query for currently “DOING” tasks (which are not “#blocked”) but I’d like to pull ones mentioning “#pinned” to the top – either by sort or by grouping – and leave ones which don’t have that tag to be sorted by date and priority.

As you can see, I started pulling out the “#pinned” block in the :where clause, to do something with it, but I can’t figure out what. Or would I somehow need to pull it out in the :result-transform? Maybe I need a has-ref? function, then I can sort by its boolean result???

{:title [:h3 "Doing"]
 :query [:find (pull ?b [*])
   :where
     [?b :block/marker ?marker]
     [(contains? #{"DOING" "NOW"} ?marker)]
     [?blocked :block/name "blocked"]
     (not [?b :block/refs ?blocked])
     [?pinned :block/name "pinned"]
     ]
 :result-transform (fn [result] (sort-by (juxt
    (fn [r] (or (get-in r [:block/scheduled]) (get-in r [:block/deadline])))
    (fn [r] (get-in r [:block/priority] "Z"))
  ) result))  ; Sort first by scheduled, then deadline, then priority.
 :table-view? false
 :group-by-page? false
 :breadcrumb-show? false
 :collapsed? false
}

For now I’ll try just highlighting the pinned ones with the :view.

One option would be sorting.
See my answer here for the basics that would entail.

Then we would need to somehow tell the database that it needs to sort by a value that is not always present. That’s the tricky part. You need something similar to the count mechanism I proposed in my post above yours.

And so probably your best option for this is two queries.
The first query will pull those tasks that are pinned.
The second query will pull those tasks that are not pinned.
This makes the results also visually distinct and so this would be a “grouping”.

I also ran into the issue of your query not returning anything. This is because your not statement needs to include the [?blocked :block/name "blocked"] to work properly. I fixed that below as well.

So then I get something like this:

#+BEGIN_QUERY
{:title [:h3 "Pinned Doing"]
 :query [:find (pull ?b [*])
   :where
     [?b :block/marker ?marker]
     [(contains? #{"DOING" "NOW"} ?marker)]
     (not 
       [?blocked :block/name "blocked"]
       [?b :block/refs ?blocked]
     )
     [?pinned :block/name "pinned"]
     [?b :block/refs ?pinned]
     ]
 :result-transform (fn [result] (sort-by (juxt
    (fn [r] (or (get-in r [:block/scheduled]) (get-in r [:block/deadline])))
    (fn [r] (get-in r [:block/priority] "Z"))
  ) result))  ; Sort first by scheduled, then deadline, then priority.
 :table-view? false
 :group-by-page? false
 :breadcrumb-show? false
 :collapsed? false
}
#+END_QUERY
#+BEGIN_QUERY
{:title [:h3 "Doing"]
 :query [:find (pull ?b [*])
   :where
     [?b :block/marker ?marker]
     [(contains? #{"DOING" "NOW"} ?marker)]
     (not 
        [?blocked :block/name "blocked"]
        [?b :block/refs ?blocked]
      )
     (not 
       [?pinned :block/name "pinned"]
       [?b :block/refs ?pinned]
     )
     ]
 :result-transform (fn [result] (sort-by (juxt
    (fn [r] (or (get-in r [:block/scheduled]) (get-in r [:block/deadline])))
    (fn [r] (get-in r [:block/priority] "Z"))
  ) result))  ; Sort first by scheduled, then deadline, then priority.
 :table-view? false
 :group-by-page? false
 :breadcrumb-show? false
 :collapsed? false
}
#+END_QUERY
1 Like

Could you please help me as well? :slight_smile:

I use Logseq for both personal and work projects with pages for each project. The difference is in the page-properties.

How do I need to modify this query that I can filter the task by page property?

- #+BEGIN_QUERY
  {:title "📎 nächste Aufgaben"
  :query [:find (pull ?b [*])
           :where
           [?p :block/name "next"]
           [?b :block/refs ?p]
           [?b :block/marker ?marker]
           [(contains? #{"NOW" "LATER" "TODO" "DOING"} ?marker)]]}
  #+END_QUERY

This one is great - I’ve swapped out the input from current-page to query-page to make it a little more stable.

I’m also wondering if there’s a way to post this on a parent of a namespace, to pull all the tasks that are tagged with the subpage aliases - for example-
parent
parent/sub - has alias: sub

so want to pull in the TODOs that have #sub, not just #parent/sub like here

PS - thank you for this thread and all your responses on other threads - I’ve been able to go from zero understanding of queries to feeling decent in only a few days going through all your templates and responses!

1 Like

Hi,
How to sort by priority with this order:

  1. Empty priority
  2. A
  3. B
  4. C

The use case is getting all new tasks (which created by default with an empty priority) on top of the priority list, for processing (like an inbox).
Empty priority can be also treated as high priority (as default A priority for new tasks is not supported)

And thanks a lot for this great thread post :+1:

Yes! That option didn’t exist back then. :+1:t3:
In general :query-page probably what you want unless you have a query on the sidebar and want it to use the page open in the main panel.

Yes. Through getting the namespace and then the alias of it.
So we’re on parent.
We can get
[?p :block/name parent]
and then
[?c :block/namespace ?p]
Then
[?c :block/alias ?a]
And finally
[?b :block/refs ?a]

Very off the top of my head quick answer.
Basically combine the info from both places.

What does your page property look like?
There should be various examples for property use/querying on this forum that may help you.

(Sorry right now I don’t have time/energy for full query writing. Hence also delay in responding at all)

1 Like

Only way is to substitute empty with “A”.
There should be sort examples that do this already.
From the top of my head (get r :block/priority "A")
This would intermingle the priority A tasks with the empty priority tasks though, as A is the first letter of the alphabet :sweat_smile:
I don’t know if something like “1” would work, but might be worth a shot.

Thank Siferiax

I searched for examples and didn’t find, maybe I missed…
Is it something with assoc function?
Ooof that bit complex for me :person_shrugging:
If you can link to me relevant code it will be great not urgent :wink:

:result-transform (fn [result] (sort-by (fn [r] (get-in r [:block/priority] "A")) result))

Or change “A” to “1” as mentioned.
It’s also in the default config sort-by-priority code, only there the default value used is “Z”.

@Siferiax thanks a lot!

It works great :slight_smile:
I can now initiate long waiting kanban board work flow, without fear newly taks will be missed :heart:

:result-transform (fn [result] (sort-by (fn [r] (get-in r [:block/priority] “1”)) result))

2 Likes

I actually ended up finding a good use for :current-page - I’m using Embed blocks for different sections of my journals, and have those embed blocks in a daily template - so I only edit the Query once and it populates across all my journals, but still gets the Current page content - absolutely brilliant, I’m loving Logseq more every day!

2 Likes

Awesome addition by @CappieXL

1 Like

Hi @Siferiax Thank you for sharing so much, it’s very much appreciated. I’ve finished going through https://www.learndatalogtoday.org/ but I’m still stuck on this advanced query to find all tasks that have an ancestor with the content “routine”. I’m curious if you can help.

#+BEGIN_QUERY
{:query [:find (pull ?b [*])
        :in $ ?s %
        :where
        [?b :block/marker ?marker]
        [(contains? #{"TODO"} ?marker)]
        ;; ancestor is true when ?ancestor is an ancestor of b
        ((ancestor ?b ?ancestor)
             [?ancestor :block/content ?str]
             [(clojure.string/includes? ?str ?s)]
            )]
:inputs
    ["routine" [[[ancestor ?b ?ancestor]
                [?b :block/parent ?ancestor]]
                [[ancestor ?b ?ancestor]
                [?child :block/parent ?ancestor]
                (ancestor ?b ?child)]]]
        }
#+END_QUERY

Do you have any tips for debugging queries or any tools that allow for deep introspection and debugging?

Thank you!

Originally posted my question here: Advanced query to get all outstanding tasks with an ancestor that contains a string

1 Like

Another useful bit I’ve built to solve a task management query problem. It was mostly a compilation of things I found on this helpful thread, so I thought I’d contribute back.

In short, it finds blocks with TODO markers that are either:

  • In a namespace of a specified page
  • Are tagged with a page tag that is in the namespace of a specified page

I’m a bit disorganized between using page tags or namespaces, and I often want to find TODOs below a given namespace, as well as pages tagged there. This solves both.

#+BEGIN_QUERY
{:title [:h4 "Find tasks in a namespace, or things that reference a namespace."]
 :query [:find (pull ?block [*])
   :in $ %
   :where
[?block :block/page ?page]

[?destpage :block/name "logseq"]
[?destpage :block/file ?origfile]

; it is a TODO
[?block :block/marker ?marker]
[(contains? #{"TODO", "DOING"} ?marker)]

; check either the page it's on, or the page it's on is tagged with a page that matches
(or-join [?page ?destpage]
(check-ns ?destpage ?page)
(and
[?page :block/tags ?pagetag]
(check-ns ?destpage ?pagetag)
)
)
 ]
 :rules [
   [(check-ns ?ns ?page)
     [?page :block/namespace ?ns]
   ]
   [(check-ns ?ns ?page)
     [?page :block/namespace ?t]
     (check-ns ?ns ?t)
   ]
 ]
}
#+END_QUERY
2 Likes

Thank you for this wealth of information!!

I am trying to simply filter out tasks with a specific tag (i.e. #[[Reading list]]), so that the journal query returns only those tasks marked as LATER which don’t have that specific tag.

I’m sure the solution is in here somewhere, but am getting a bit lost and would appreciate some help…

{:title "📅 LATER"
    :query [:find (pull ?h [*])
            :in $ ?start ?next
            :where
            [?h :block/marker ?marker]
            [(contains? #{"LATER" "TODO"} ?marker)] 
            [?h :block/page ?p]
            [?p :block/journal? true]
            (not [?h :block/refs ?t] 
                 	[?t :page/name "reading list"]) 
            [?p :block/journal-day ?d]
            [(> ?d ?start)]
            [(< ?d ?next)]]
    :inputs [:365d :today]
    :result-transform (fn [result]
                        (sort-by (fn [h]
                                   (get h :block/priority "Z")) result))
    :group-by-page? false
    :collapsed? true}]}
2 Likes

:view (fn [r] [:pre.code (pprint r)])
Will show you the output of your query more directly which can help.
I’ll have a look at the topic and reply there :slight_smile:

Does the query you posted work for you? Or do you need further help?

3 Likes