Queries for task management

Yes, with some caveats.
The query will always run. However upon refresh it may or may not show content.

I use it to show start of day and end of day reflection. So most of the time this query shows “no matched results”. But at specific times it does.

#+BEGIN_QUERY
{:title [:h4 "🧘🏽‍♀️ Reflectie"]
 :query [:find (pull ?b [*])
  :in $ ?now ?o ?a
  :where
   [?p :block/name "reflectie"]
   [?b :block/page ?p]
   [?b :block/content ?c] ;blocks on page reflectie with certain content
   (or   ; different rules to validate against
     (and
       [(<= ?now ?o)] ; now is before 13:00
       [(clojure.string/includes? ?c "Begin van de dag")] ;block includes this content
     )
     (and
       [(<= ?a ?now)] ; now is after 17:30
       [(clojure.string/includes? ?c "Eind van de dag")] ;block includes this content
     )
   ) ;If none of this is true, show nothing
 ]
 :result-transform (fn [r] (map (fn [m] (assoc m :block/collapsed? true)) r)) ;show the block collapsed
 :inputs [:right-now-ms :today-1300 :today-1730] ;the time now, at 13:00 and 17:30
}
#+END_QUERY

You can change the conditions as you wish obviously. Hopefully this provides a good starting point.
If you need more specific help, let me know!

Ps. Let me mention that I have an extremely complex set up using the same idea.
It has 7 inputs, one is today, the rest is times. Showing different things at different times, but also based on other conditions… :sweat_smile:

3 Likes

Hi thank you for this. I’ve been playing around with the code, I get it to work, but not to show up between the appropriate hours I want it to show up. If I write “:today” in inputs the query shows results, which confirms my code works overall, but when I use your inputs it doesn’t work. Here’s something I tried:

:inputs [:right-now-ms :today-0700 :today-1700] ;display reults from 07:00 to 17:00

Also not working.

I also tried:
:inputs [:today-0700 :today-1700] ;display reults from 07:00 to 17:00.

not working !! :frowning: I’ve been reading https://docs.logseq.com/#/page/advanced%20queries but I do not see what it is that I do wrong.

Again, just to be clear, here’s what I’m trying to do: “If it is between 7am and 5pm, execute this query.”

Hi, what does the rest of the query look like?
I cannot help you based on this information alone I’m afraid.
What is in :inputs corresponds with what is behind :in $

So in my example we have
:in $ ?now ?o ?a
:inputs [:right-now-ms :today-1300 :today-1730]

Meaning ?now will have the value of :right-now-ms, ?o will have the value of :today-1300 and ?a has the value of :today-1730.

These are then used together, for example here:
[(<= ?now ?o)] to determine if that is true or false. In this case is it right now (on your device) before or at 1300.

So yeah, without more details, this is all I can tell you.

This is the thing i’m trying to pull off… get all tasks from maison page after 16:00… I’m pulling my hair off!!

{:title [:h4 "🧘🏽‍♀️ Reflectie"]
     :query [:find (pull ?h [*])
     :in $ ?now ?a
     :where
     [?h :block/marker ?marker]
     [(contains? #{"NOW" "LATER"} ?marker)]
     [?p :block/name "maison"]
     [?b :block/page ?p]
     (or   ; different rules to validate against
       (and
         [(>= ?a ?now)] ; now is before 18:00
       )
     ) ;If none of this is true, show nothing
     ]
     :result-transform (fn [r] (map (fn [m] (assoc m :block/collapsed? true)) r)) ;show the block collapsed
     :inputs [:right-now-ms :today-1800] ;the time now, at 13:00 and 17:30
     :collapsed? true
    }

So 2 things. 1 you put the blocks on the maison page in variable ?b, but you pull ?h.
And you don’t need the and or or, because there is only 1 condition.

Here’s what it should look like:

#+BEGIN_QUERY
{:title [:h4 "🧘🏽‍♀️ Reflectie"]
 :query [:find (pull ?h [*])
  :in $ ?now ?a
  :where
   [?h :block/marker ?marker]
   [(contains? #{"NOW" "LATER"} ?marker)]
   [?p :block/name "maison"]
   [?h :block/page ?p]
   [(>= ?a ?now)] ; now is before 18:00
 ]
 :result-transform (fn [r] (map (fn [m] (assoc m :block/collapsed? true)) r)) ;show the block collapsed
 :inputs [:right-now-ms :today-1800] ;the time now and at 18:00
 :collapsed? true
}
#+END_QUERY

Ps. Don’t pull your hair out. That’s not healthy!

1 Like

Alternative, more simple query can be found here.

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.

4 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