- Custom predicates
- Agenda-like view
- Entries from the past week
- Find entries matching a certain CUSTOM_ID
- Listing bills coming due
- Music database
- Return Org elements
- Set tags on certain entries
- Show entries with recent timestamps
- Stuck projects block agenda
- Subproject and subtask queries
- Task list for files in subdirectories
Show an agenda-like view, similar to a “traditional” Org Agenda with Log Mode turned on.
(org-ql-search (org-agenda-files)
'(or (and (not (done))
(or (habit)
(deadline auto)
(scheduled :to today)
(ts-active :on today)))
(closed :on today))
:sort '(date priority todo))
Another example, showing grouping with org-super-agenda:
(org-ql-search "~/src/emacs/org-super-agenda/test/test.org"
'(and (or (ts-active :on today)
(deadline auto)
(scheduled :to today))
(not (done)))
:title "My Agenda View"
;; The `org-super-agenda-groups' setting is used automatically when set, or it
;; may be overriden by specifying it here:
:super-groups '((:name "Bills"
:tag "bills")
(:todo ("SOMEDAY" "TO-READ" "CHECK" "TO-WATCH" "WATCHING")
:order 7)
(:name "Personal"
:habit t
:tag "personal"
:order 3)
(:todo "WAITING"
:order 6)
(:priority "A" :order 1)
(:priority "B" :order 2)
(:priority "C" :order 2)))
Which displays this buffer:
Show entries that have any timestamp within the past week. Group by date using org-super-agenda
with the :auto-ts
group.
(org-ql-search (org-agenda-files)
'(ts :from -7 :to today)
:title "Recent Items"
:sort '(date priority todo)
:super-groups '((:auto-ts t)))
Since queries can contain both built-in org-ql
predicate expressions and arbitrary expressions, they can be combined in useful ways. This example uses the built-in property
predicate to quickly locate entries that have the CUSTOM_ID
property set, and then compares the value of that property to the string issue
.
(org-ql-query
:select #'org-get-heading
:from "~/org/tickets.org"
:where '(and (property "CUSTOM_ID")
(string-match "issue" (org-entry-get (point) "CUSTOM_ID"))))
Using the property
predicate as the first clause of the two clauses joined with and
allows org-ql
to optimize the query by searching through the buffer directly to entries that set the CUSTOM_ID
property, which is much faster than testing every entry in a buffer. Also, If the query were only the string-match
call, it would signal an error on entries that didn’t have the property set, because org-entry-get
would return nil.
This uses the example in the readme file, but maps across the elements returned by org-ql
to present a simple list of titles and deadlines.
(org-ql-query
:select '(list (substring-no-properties (org-get-heading t t))
(org-entry-get (point) "DEADLINE"))
:from (org-agenda-files)
:where '(and (not (done))
(tags "bills")
(deadline auto))
:order-by 'deadline)
;;=> (("Electric bill" "<2018-08-23 Thu +1m>")
;; ("Rent" "<2018-09-01 Sat +1m>"))
This could also be put in a script, which could use desktop notifications to remind of bills coming due: org-bills-due.el.
If you kept a database of music in an Org file, you could run a query like this to find tracks composed by Chopin that do not have their key recorded in the database.
(org-ql-search "~/org/music.org"
'(and (property "genre" "classical")
(property "composer" "Chopin")
(not (property "key"))))
Return a list of Org entry elements in the file ~/org/main.org
which have the SOMEDAY
to-do keyword, are tagged Emacs
, and have priority B or higher. org-ql
is the macro version of org-ql-select
; it does not require quoting the query sexp.
(org-ql "~/org/main.org"
(and (todo "SOMEDAY")
(tags "Emacs")
(priority >= "B")))
;;=> ((headline (:raw-value "org-board" :begin 1220270 :end 1220403 ...)) ...)
Set the tag Emacs
on every entry in the inbox file that mentions Emacs
. The bare-string query "Emacs"
is equivalent to (regexp "Emacs")
.
(org-ql-select "~/org/inbox.org"
"Emacs"
:action '(org-toggle-tag "Emacs" 'on))
You can also access these views with the command org-ql-view
.
;; Show entries with any timestamp from last 7 days:
(org-ql-view-recent-items 7)
;; Show entries clocked in last 30 days:
(org-ql-view-recent-items 30 'clocked)
;; Show entries closed in last 30 days:
(org-ql-view-recent-items 30 'closed)
Reddit user emptymatrix
shared this example of replacing a traditional org-stuck-projects
view like:
(setq org-stuck-projects
'("+@project/-DONE" ("NEXT") nil "SCHEDULED:"))
With this org-ql-block
agenda view, like:
(setq org-agenda-custom-commands
'(("s" "Stuck Projects"
((org-ql-block '(and (tags "@project")
(not (done))
(not (descendants (todo "NEXT")))
(not (descendants (scheduled))))
((org-ql-block-header "Stuck Projects")))))))
;; Search for subprojects.
(org-ql-search (org-agenda-files)
'(and (todo "PROJECT")
(ancestors (todo "PROJECT"))))
;; Search for all subtasks of projects, grouped by parent heading.
(org-ql-search (org-agenda-files)
'(and (todo)
(ancestors (todo "PROJECT")))
:super-groups '((:auto-parent t)))
;; Search for direct top-level tasks of projects.
(org-ql-search (org-agenda-files)
'(and (todo)
(parent (todo "PROJECT")))
:super-groups '((:auto-parent t)))
Of course, all of those presume using a PROJECT
keyword to define projects. If one defines a project as any task which has an ancestor task, one could use queries like:
;; Search for all subtasks of top-level projects, grouped by parent heading.
(org-ql-search (org-agenda-files)
'(and (todo)
(ancestors
(and (todo)
(not (parent)))))
:super-groups '((:auto-parent t)))
;; Search for all subtasks of all projects, including subprojects, grouped by project.
(org-ql-search (org-agenda-files)
'(and (todo)
(ancestors (todo)))
:super-groups '((:auto-parent t)))
Other interesting queries:
;; Subtasks of upcoming deadline items.
(org-ql-search (org-agenda-files)
'(and (todo)
(ancestors
(and (not (done))
(deadline auto))))
:super-groups '((:auto-parent t)))
;; TODO items whose ancestor is already DONE, and should therefore be
;; either marked DONE or CANCELLED.
(org-ql-search (org-agenda-files)
'(and (todo)
(ancestors (done)))
:super-groups '((:auto-parent t)))