Queries for task management

I’m going to gather some queries here that will be useful for task management.
It won’t be done in one go and I will be adding inline comments to help you understand what is going on. I have added those to build on the queries in order. So read through them all as I have only added comments the first time a statement appeared.
Hopefully this will help you be able to edit the queries for yourself.

Tasks past due

Tasks scheduled value is past due (based on today)

#+BEGIN_QUERY
{:title [:h3 "🔥 Past scheduled"]
 :query [:find (pull ?b [*])
   :in $ ?day  ; ?day is the name for the first value in inputs further down.
   :where
     [?b :block/marker "TODO"]  ; Using TODO straight in the clause because I want marker to be a specific value.
     [?b :block/scheduled ?d]  ; the block ?b has attribute scheduled with value ?d
     [(< ?d ?day)]  ; the value ?d is smaller than the value ?day
 ]
 :inputs [:today]  ; use the Logseq dynamic variable :today as input for this query (gives today's date as yyyymmdd format)
 :table-view? false
}
#+END_QUERY

Open scheduled tasks

#+BEGIN_QUERY
{:title [:h3 "✅ Planned"]
 :query [:find (pull ?b [*])
 :where
   [?b :block/marker ?marker]
   [(contains? #{"TODO" "LATER"} ?marker)]  ; TODO put in a value list with LATER.
   [?b :block/scheduled ?d]  ; ?b has attribute scheduled with value ?d, ?d is not further specified and so is any value. The same can be accomplish with _
 ]
 :result-transform (fn [result] (sort-by (fn [r] (get-in r [:block/scheduled])) result)) ; sort the result by the scheduled date
 :table-view? false
 :breadcrumb-show? false  ; don't show the parent blocks in the result !important, due to result-transform the grouping is lost, and so you will be left with a simple list of TODO items. having those parents blocks mixed in may make the list more confusing. (setting this to true won't show the page btw!)
 :collapsed? false
}
#+END_QUERY

Open unplanned tasks from journal pages

#+BEGIN_QUERY
{:title [:h3 "☑ Unplanned"]
 :query [:find (pull ?b [*])
 :in $ ?day
 :where
   [?p :block/journal-day ?d]  ; ?p has the attribute journal-day with value ?d (you don't need the :block/journal? attribute if you also use this one)
   [(< ?d ?day)]
   [?b :block/page ?p]  ; ?b has the attribute :block/page with value ?p, ?p has been define with the identifier of a journal page above.
   [?b :block/marker "TODO"]
   (not [?b :block/scheduled _])  ; ?b doesn't have the attribute scheduled (_ is used to say that the value doesn't matter. If a value is specified it would read as ?b may have the attribute, but not with that value)
 ]
 :result-transform (fn [result] (sort-by (fn [r] (get-in r [:block/page :block/journal-day])) result))  ; Sort by the journal date
 :inputs [:today]
 :table-view? false
 :breadcrumb-show? false
 :collapsed? false
}
#+END_QUERY

Yesterday’s open tasks

Tasks open from yesterday’s journal page, that don’t have a deadline/scheduled date or their deadline/scheduled date was yesterday.

#+BEGIN_QUERY
{:title [:h3 "🔥 Yesterday's open tasks"]
 :query [:find (pull ?b [*])
 :in $ ?day
 :where
   [?p :block/journal-day ?day]  ; Here we input the value of the input into the clause immediately as it is an = statement.
   [?b :block/page ?p]
   [?b :block/marker "TODO"]
   (or
     [?b :block/scheduled ?day]  ; Either the scheduled value is equal to ?day
     (not [?b :block/scheduled])  ; or the scheduled attribute doesn't exist (_ is omitted here, it is instead implied)
   )
   (or
     [?b :block/deadline ?day]  ; same as above, but for the deadline attribute.
     (not [?b :block/deadline])
    )
 ]
 :inputs [:yesterday]
 :table-view? false
}
#+END_QUERY

Deadline to be scheduled

Not yet scheduled with deadline on certain day (I use the coming Sunday as a date)

#+BEGIN_QUERY
{:title [:h3 "🎯 Not yet planned"]
 :query [:find (pull ?b [*])
 :in $ ?day
 :where
   [?b :block/deadline ?d]
   [(<= ?d ?day)]
   [?b :block/marker "TODO"]
   (not [?b :block/scheduled _])
]
  :result-transform (fn [result] (sort-by (fn [r] (get-in r [:block/deadline])) result))
  :breadcrumb-show? false
  :table-view? false
  :inputs [20230212]
}
#+END_QUERY

Scheduled with deadline

Planned, with deadline on certain date (again I use the next Sunday)

#+BEGIN_QUERY
{:title [:h3 "🎯 Planned"]
 :query [:find (pull ?b [*])
 :in $ ?day
 :where
   [?b :block/deadline ?d]
   [(<= ?d ?day)]
   [?b :block/marker "TODO"]
   [?b :block/scheduled _]
 ]
 :result-transform (fn [result] (sort-by (juxt (fn [r] (get-in r [:block/scheduled])) (fn [r] (get-in r [:block/deadline])) ) result))  ; Sort first by scheduled and then by deadline.
 :breadcrumb-show? false
 :table-view? false
 :inputs [20230212]
}
#+END_QUERY

Todo in sub block

Sorting options for simple deadline/scheduled query

Tasks that have specific page reference

#+BEGIN_QUERY
{:title [:h3 "Tasks with page reference" ]
 :query [:find (pull ?b [*])
    :where
      [?p :block/name "page"] ; name is always lowercase
      [?b :block/refs ?p] ; this block references ?p as oppose to being on ?p through :block/page.
      [?b :block/marker "TODO"]
 ]
}
#+END_QUERY

Tasks without a specific page link

#+BEGIN_QUERY
{:title [:h3 "Tasks without page reference" ]
 :query [:find (pull ?b [*])
   :where
     [?p :block/name "page"] ; name is always lowercase
     [?b :block/marker "TODO"]
     (not [?b :block/refs ?p]) ; we cannot use not until we have specified the variables used in it
 ]
}
#+END_QUERY

Unscheduled non-project tasks

Tasks that are not scheduled and not on a page with tags:: projecten (this property creates page links)

#+BEGIN_QUERY
{:title [:h3 "🔔 Ongeplande taken"]
 :query [:find (pull ?b [*])
   :where
     [?b :block/marker "TODO"]
     (not [?b :block/scheduled])
     [?b :block/page ?p]
     [?pr :block/name "projecten"]
     (not [?p :block/tags ?pr])
 ]
 :table-view? false
}
#+END_QUERY

Tasks by current page & it’s aliases

This uses a more complex or statement. This is basically a logical or. it is needed here as variable ?a is only for use in the or. [?b ?p] means these two variables are bound with the rest of the query.
More information: Datomic Queries and Rules | Datomic

#+BEGIN_QUERY
{:title ["Query by page & alias"]
 :query [:find (pull ?b [*])
   :in $ ?page
   :where
     [?b :block/marker "TODO"]
     [?p :block/name ?page]
     (or-join [?b ?p]
       [?b :block/refs ?p] 
       (and [?p :block/alias ?a] ; this attribute is available only when alias:: has been specified as a page property.
          [?b :block/refs ?a])
     )
 ]
 :result-transform :sort-by-priority
 :table-view? false
 :inputs [:current-page] ; alternatively use :query-page to use the page the query is on, rather than the page you are viewing
}
#+END_QUERY

Suggestions welcome! Also do link to other threads on the forum with similar questions. Let’s make this a task management resource for everyone to easily find and reference!

Thanks for sharing, it’s very much appreciated

1 Like

3 more queries added.
Also please note that starting at version 0.8.17 dynamic query inputs have changed and expanded!!

Please see here for details:
https://docs.logseq.com/#/page/advanced%20queries/block/query%20inputs

4 Likes

Just going to add queries in new posts as the first one is getting long :stuck_out_tongue:

All tasks that have a deadline and aren’t done or canceled.

#+BEGIN_QUERY
{:title [:h3 "Deadline"]
 :query [:find (pull ?b [*])
 :where
   [?b :block/deadline ?d]
   [?b :block/marker ?m]
   (not [(contains? #{"DONE" "CANCELED"} ?m)])
 ]
}
#+END_QUERY

Tasks with their page name

A little bit more of an advanced query, using a view to make a table of the page name and task.
It will get rid of the checkbox unfortunately, but the task is clickable to navigate to it.

#+BEGIN_QUERY
{:title "Task on page"
 :query [:find (pull ?b [*])
   :where
     [?b :block/marker "TODO"]
     [?b :block/page ?p]
 ]
 :result-transform (fn [result] (sort-by (fn [d] (get d :block/page :block/original-name)) result))
 :view (fn [rows] [:table [:thead [:tr [:th "Page"] [:th "Task"] ] ]
   [:tbody (for [r rows] [: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])] 
     ]
     [:td [:a {:href (str "#/page/" (get r :block/uuid))} (get r :block/content)]]
   ])
 ]])
}
#+END_QUERY
2 Likes

Hi! I have pasted several of the queries in my edn configuration page and i am getting always the same message: Make sure your config is wrapped
in {}. Also make sure that the characters ‘( { [’ have their corresponding closing character ‘) } ]’. I am starting with the #+BEGIN_QUERY and ending with #+END_QUERY. What could be wrong? Thanks !

Hi! Easy. In the config you don’t use begin and end query. Just discard those lines :slight_smile:
Those are needed when you paste them on a page.
See the same for the default queries that are in the config file.

1 Like

I am having the same issue by copying/pasting the query… Should the lines be indented as you mention ?

1 Like

Very useful examples, thanks a lot. Is there a reason why you used

[?b :block/marker "TODO"]

and not the more current shorthand

[task ?b #{"TODO"}]

which also allows for querying several states easily, e.g.

[task ?b #{"TODO" "LATER" "WAITING" "WAIT"}]

I’ve deleted all config queries for visual aid.
Make sure to paste the entire query from { till } and without the #+BEGIN_QUERY and #+END_QUERY between this part of the config:

:default-queries
 {:journals
  [
; So right here!
   ]}

Yes, part clarity, part personal preference.
The “shorthand” you suggest is actually an implementation of a simple query into an advanced query.
My opinion is to stick to either one and not combine them. It leads to confusion and user error from what I have seen.
In the backend it gets all converted to advanced query anyway.

As for your point about lists, please see the second query in the first post for how to do the same with advanced syntax.

Thanks a lot! I’ve got it.

2 Likes

Clearly one of THE MOST USEFUL posting I’ve ever read for Logseq queries. Thank you very much. A great learning opportunity, courtesy YOU.

2 Likes

A fun one today!

Tasks that don’t reference a page regardless of nesting

This will exclude any tasks that are referencing a page or that one of the parent blocks references a page. This query uses rules for recursive searching.
To change this to reference instead of don’t reference, just remove the (not and closing ) around (check-ref ?p ?b)

#+BEGIN_QUERY
{:title "🔨 TODO"
 :query [:find (pull ?b [*])
   :in $ % ; % is used to pull in the rules below.
   :where
     [?b :block/marker ?marker]
     [(contains? #{"TODO"} ?marker)]
     ;; Exclude pagename
     [?p :block/name "pagename"]
     (not (check-ref ?p ?b)) ; this calls the rules below.
 ]
 :rules [ ; whenever two rules have the same name an or is applied. I'm not exactly sure how to explain it!
   [(check-ref ?p ?b) ; definition of the rule, name and parameters.
     [?b :block/refs ?p] ; rule content to be executed
   ]
   [(check-ref ?p ?b)
     [?b :block/parent ?t]
     (check-ref ?p ?t) ; calling the rule again within this rule will make it recursive.
   ]
 ]
 :breadcrumb-show? false
 :collapsed? true
}
#+END_QUERY
2 Likes

Hi,
I added one of your queries (past deadline) and it worked.
Somehow, I am not sure why but the queries do not work anymore.

NOW works,
Past deadline does not
NEXT does not work either I believe

See the code here:

Blockquote
:default-queries
{:journals
[{:title “:hammer: 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 [:h3 “:fire: Past scheduled”]
:query [:find (pull ?b [
])
:in $ ?day ; ?day is the name for the first value in inputs further down.
:where
[?b :block/marker “TODO”] ; Using TODO straight in the clause because I want marker to be a specific value.
[?b :block/scheduled ?d] ; the block ?b has attribute scheduled with value ?d
[(< ?d ?day)] ; the value ?d is smaller than the value ?day
]
:inputs [:today] ; use the Logseq dynamic variable :today as input for this query (gives today’s date as yyyymmdd format)
:table-view? false}
{:title “:date: 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}]}

Could you help me out, please
(not sure why the indentation is not show once posted, when I insert the code in edit mode I see the indentation

Thank you so much!! Really helped my workflow to the next level! Dankjewel :star_struck:

1 Like

For indentation to show you put the code between 3 backticks:
```
Like so.
```
To turn it into

Like so.

Anyway…
The query looks fine.
If you’re not getting a result, it could be an issue with the data.
What data do you have that you expect to be returned?
The past scheduled only shows TODO tasks with a scheduled date before today.
The Next shows only tasks on future journal dates. (Which is a really weird default query, considering journal pages are generated the day of and not in the future, but that is an aside.)

2 Likes

As you can see I have:

the standard NOW:
works fine. Shows a task that is DOING.

Your PAST DEADLINE:
Not ok. I have a task with deadline on the 14th but it doesn’t show up in today’s journal in PAST DEADLINE.

the standard NEXT:
Not sure if it works as I also have the standard SCHEDULED AND DEADLINE
when should what show up.

So my real issue is past deadline.

My ideal setup would include

NOW
the ones with status DOING

PAST DEADLINE
all tasks with deadline in the past when not DONE (this way I include also WAITING)

SCHEDULED AND DEADLINE
the ones scheduled for today and the days to come (I think default is 14?)

It is past scheduled and not past deadline :sweat_smile:
For things with a deadline in the past you have to replace the :block/scheduled with :block/deadline.
As for the not done part.
Change [?b :block/marker "TODO"] to (not [?b :block/marker "DONE"])
Or alternatively to

[?b :block/marker ?m]
(not [(contains? #{"DONE" "CANCELED"} ?m)])

To also filter out canceled tasks.

1 Like

The next query doesn’t look at scheduled or deadline. It just looks at tasks in journal pages that are into the future. Which unless you make those yourself don’t even exist.

1 Like

Ah! I see ! I have to admit I am still figuring out the task management.
So scheduled would be planned where deadline it needs to be done latest at that day right?
Actually I would even prefer to see both in that same query based on the date. So basically it would be a “Past date” or “overdue” regardless of scheduled or deadlines. Both need immediate review.

Thanks for your help. Really appreciate it

1 Like