Queries for task management

Tasks that do or do not repeat with specific tag

1 Like

That thread is a goldmine! Thank you so much @Siferiax I wonder if you could help me out. I managed to put together a query that looks for “next actions” as per the GTD terminology and keep only these “next actions” related to projects with deadlines. I just can’t seem to sort the list by :block/deadline of these ancestor blocks in the :result-transform section as the “next actions” don’t really inherit the deadlines themselves from the ancestor tasks… Here’s my query so far:

#+BEGIN_QUERY
{:title [:h2 "NEXT ACTIONS of projects w/ deadlines"]
:query [:find (pull ?b [*])
        :in $ % 
        :where
        [?b :block/marker ?marker]
        [(contains? #{"LATER" "NOW"} ?marker)]
        ;; descendant is true when ?descendant is an descendant of b

        (not [?descendant :block/parent ?b]
             [?descendant :block/marker ?amarker]
             [(contains? #{"LATER" "NOW"} ?amarker)])

(ancestor ?b ?ancestor)
[?ancestor :block/deadline ?d]
]


:inputs
   
  [[

    [(ancestor ?b ?ancestor)
				[?b :block/parent ?ancestor]]
	
    [(ancestor ?b ?ancestor)
	            [?child :block/parent ?ancestor]
	            (ancestor ?b ?child)]
]]

:result-transform  (fn [result]
                            (sort-by  
(juxt
(fn [d] (get d :block/deadline)) 
(fn [h] (get-in h [:block/properties :time]))
) < result)
)
:collapsed? false
}
#+END_QUERY#

We need to associate that deadline property with the result you get.
This happens in the :find, :keys and most importantly :result-transform of the below query.

#+BEGIN_QUERY
{:title [:h2 "NEXT ACTIONS of projects w/ deadlines"]
 :query [:find (pull ?b [*]) ?d
   :keys block deadline
   :in $ % 
   :where
     [?b :block/marker ?marker]
     [(contains? #{"LATER" "NOW"} ?marker)]
     ;; descendant is true when ?descendant is an descendant of b
     (not 
       [?descendant :block/parent ?b]
       [?descendant :block/marker ?amarker]
       [(contains? #{"LATER" "NOW"} ?amarker)]
     )
     (ancestor ?b ?ancestor)
     [?ancestor :block/deadline ?d]
 ]
 :inputs [ [
   [(ancestor ?b ?ancestor)
     [?b :block/parent ?ancestor]
   ]
   [(ancestor ?b ?ancestor)
     [?child :block/parent ?ancestor]
     (ancestor ?b ?child)
   ]
 ] ]
 :result-transform (fn [result]
   (sort-by  
     (juxt
       (fn [d] (get-in d [:block/properties :deadline])) 
       (fn [h] (get-in h [:block/properties :time]))
     )
     < 
; the below associates the deadline key from the query result with the :block/properties attribute from the block key. Which we use above in the sort.
     (map 
       (fn [m]
         (update (:block m) :block/properties
           (fn [u] (assoc u :deadline (get-in m [:deadline]) ) )
         )
       ) 
       result 
     )
   )
 )
 :collapsed? false
}
#+END_QUERY

Things are broken in version 0.9.2, but older versions should work correctly.
Let me know if you encounter any issues!

1 Like

@Siferiax - Sorry to bother you, but I just wanted to follow up on this in case you missed it! With table view, the only columns I see are “block” and “page” but is there any way to see more columns like “deadline”, “priority”, etc.?

Yes I had that on my backlog, but a bunch of other things came on my plate at the same time and I sort of lost track of it. Thanks for the reminder!
I put it off as it is not a simple answer :slight_smile: but definitely should be possible with some magic trickery!
Table view in default will only show block, page and any used properties, not other values. However we can build our own tables in advanced queries!

Here’s the whole thing:

#+BEGIN_QUERY
{:title "🟠 SLIPPING"
 :query [:find (pull ?b [*])
   :in $ ?start ?today
   :where
     (task ?b #{"NOW" "LATER" "TODO" "DOING"})
     (between ?b ?start ?today)
 ]
 :inputs [:-7d :today]
 :result-transform (fn [result] (sort-by (fn [h] (get h :block/created-at)) result ) )
 :view (fn [rows] [:table 
   [:thead [:tr 
     [:th "Page"]
     [:th "Task"]
     [:th "Priority"]
     [:th "Deadline"]
   ]] 
   [:tbody (for 
     [r rows
       :let [content (str (get r :block/content))]
       :let [firstline (first (str/split-lines content))] ;this will show only the first line of the task.
     ]
     [:tr
       [:td [:a {:href (str "#/page/" (clojure.string/replace (get-in r [:block/page :block/original-name]) "/" "%2F"))}
 (get-in r [:block/page :block/original-name])] ] ;make a workable link to the page, even when it is in a namespace
       [:td [:a {:href (str "#/page/" (get-in r [:block/uuid]))} firstline] ] ;link to the block and show the first line
       [:td (get r :block/priority) ] ;get the priority from the results
       [:td (get r :block/deadline)] ;get the deadline from the results
     ]
   )]
 ])
 :collapsed? false
}
#+END_QUERY

You can expand it with any block attributes available basically.

2 Likes

Thank you so much! I’ll try it out ASAP. You’re very knowlegeable in Datalog. I would love to get to that level of mastery and give back to the Logseq community. What ressources would you recommend based on your own journey to go beyond a simple introduction to Datalog just to get by? I have no background in programming but I would love to learn. Thank you!

Start here: http://www.learndatalogtoday.org/
Then check out these resources: https://siferiax.github.io/#/page/logseq%2Fadvanced%20queries/block/sources%20(external)
Especially Datomic Queries and Rules | Datomic I still reference a lot to this day.
As well as the Clojure docs for the functions.
I also have a collection of references I use frequently: https://siferiax.github.io/#/page/logseq%2Fadvanced%20queries
As well as a collection of examples: https://siferiax.github.io/#/page/logseq%2Fquery%20tests
I do admit I haven’t updated my site in awhile with new queries though.

4 Likes

As usual, I can’t thank you enough for your help. Thank you for being one of the most amazing people on this forum! :blush:

2 Likes

Hello! This works perfectly. I just wonder how can I make the query results collapsed by default? Thanks for your help!

add to your advanced query

:collapsed? true

I don’r want to collapse the query itself, just block results! Thank though

@Matthieu_B changed the result-transform for this.

 :result-transform (fn [result]
   (sort-by  
     (juxt
       (fn [d] (get-in d [:block/properties :deadline])) 
       (fn [h] (get-in h [:block/properties :time]))
     )
     < 
     (map (fn [m] (assoc m :block/collapsed? true))
     (map 
       (fn [m]
         (update (:block m) :block/properties
           (fn [u] (assoc u :deadline (get-in m [:deadline]) ) )
         )
       ) 
       result
     ) )
   )
 )
1 Like

Thank you so much! It works as expected!

Hmmm with 0.9.4 this will probably do the same?

Add :remove-block-children? query option for advanced queries

Is there a way to show tasks results in a table, where I can click in their checkboxes?

Not that I’m aware of.
Though with :group-by-page? false (newest Logseq version) and :breadcrumb-show? false you should just get a list of tasks.

Full query:

#+BEGIN_QUERY
{:title "List of tasks"
 :query [:find (pull ?b [*])
   :where
     [?b :block/marker ?m]
     (not [(contains? #{"DONE" "CANCELED"} ?m)] )
     (not 
       [?b :block/parent ?par]
       [?par :block/marker]
     )
 ]
 :group-by-page? false
 :breadcrumb-show? false
}
#+END_QUERY
4 Likes

I have a query that looks for all the blocks in the journal, that are not a task, and have a reference to the page where the query is, I want to mark some of the blocks with a tag to hide them from the query (because they become useless to my reports). I have tried a lot of things, but I can’t make the query to filter any block tagged with the #hd … can you give me a hint?

#+BEGIN_QUERY
{ :title [:h3 “Notas Adicionales” ]
:query [:find (pull ?b [*])
:in $ ?page
:where
[?x :block/name ?page]
(or-join [?b ?x]
[?b :block/refs ?x]
(and [?x :block/alias ?page] [?b :block/refs ?x])
)
(not [?b :block/marker _])
(not [?child :block/marker _] [?b :block/children ?child])
(not [?b :block/page ?p2] [?p2 :page/journal? false])
]

:group-by-page? true
:result-transform :sort-by-priority
:table-view? false
:breadcrumb-show? false
:inputs [:query-page]
}
#+END_QUERY

Hey, I’ve just started using logseq and I’m already hooked. This query is exactly what I was missing on the journal page. Only I would like the list to be sorted by scheduled date in descending order and limited to 7d in the future. How can I do that? Thanks for your help.

:block/children is not a valid attribute.
You need to go the other way with :block/parent.
Also how you checked the alias was incorrect.

I’ve rewritten the query for you. Let me know if this gives what you are looking for!

#+BEGIN_QUERY
{:title [:h3 "Notas Adicionales"]
 :query [:find (pull ?b [*])
   :in $ ?page
   :where
     [?x :block/name ?page]
     (or-join [?b ?x]
       [?b :block/refs ?x]
       (and 
         [?x :block/alias ?a] 
         [?b :block/refs ?a]
       )
     )
     [?b :block/page ?p] 
     [?p :block/journal? true]
     (not [?b :block/marker _])
     (not 
       [?child :block/parent ?b]
       [?child :block/marker _]
     )
     (not 
        [?b :block/refs ?tag]
        [?tag :block/name "hd"]
     )
 ]
 :group-by-page? true
 :result-transform :sort-by-priority
 :table-view? false
 :breadcrumb-show? false
 :inputs [:query-page]
}
#+END_QUERY
2 Likes

Great to hear you enjoy it :slight_smile:
Two questions.

  1. Which way is descending? Oldest to newest or newest to oldest
  2. What way do you want to limit the tasks? Based on what journal page they are on? Or based on their scheduled date?
1 Like