Tag based task aggregator

This one was really fun to build. As mentioned in my previously shared query (Advanced Query that pulls all reference AND recursive name spaces - #5 by CappieXL ), the way queries, namespaces, and aliases work together makes it hard for me to get it working to my liking. Therefore, I tried to go another route and instead of name spaces aggregate tasks based on page-tags.

I call this the “tag-based task aggregator”. Basically what it does, is that it collects all the tasks that are:

  1. on the current-page; or
  2. path-reference the current-page; or
  3. are on a page that has the current page as a tag; or
  4. path-reference a page that has the current page as a tag.

So imagine you’re working at “Bedrijf A”, which does a project “Project A.X” together with a client “Klant X”. If you’re like me, you jot everything down in the daily journal. So if my client calls me, I quickly make a task and I tag the project. Because the project has a page tag to both Bedrijf A and Klant X, the task will land on their task lists too.

Here are some screenshots:





To me this has two major advantages:

  1. I do not need to clutter my workflow with very long nested namespaces
  2. It becomes really intuitive. I can create project pages and just tag all the task lists i would like those tasks to show up.

Here’s the query:

#+BEGIN_QUERY
{:title "?currentpage taken"
:query [:find (pull ?b [*])
:in $ ?current-page
   :where
(task ?b #{"NOW" "LATER" "DOING" "TODO"})
(?p :block/name ?current-page)
(or
(and [?page :block/name ?page] [?b :block/path-refs ?p] )
(and (?page :block/tags ?p) [?b :block/path-refs ?page])
)
]
:result-transform (fn [result] (sort-by (fn [r] (get r :block/content)) result))
:group-by-page? false
:breadcrumb-show? false
:inputs [:current-page]
}
#+END_QUERY

It seems you use this, because the query throws an error.
However this is not the correct solution to that. Instead your or should be an or-join, like this.

(or-join [?p ?b]
  [?b :block/path-refs ?p]
  (and 
    [?page :block/tags ?p] 
    [?b :block/path-refs ?page]
  )
)

To explain, an or statement will be bound to the rest of the query.

“All clauses used in an or clause must use the same set of variables, which will unify with the surrounding query. This includes both the arguments to nested expression clauses as well as any bindings made by nested function expressions. Datomic will attempt to push the or clause down until all necessary variables are bound, and will throw an exception if that is not possible.”
From Datomic Queries and Rules | Datomic
(Although Logseq uses the datascript implementation and not datomic, they are similar.)

“An or-join is similar to an or clause, but it allows you to specify which variables should unify with the surrounding clause; only this list of variables needs binding before the clause can run. The variables specifies which variables should unify.”

In our case it is the variables ?p and ?b. So we write or-join [?p ?b]
The variable ?page is only relevant within the or-join.

Otherwise yes, tags and direct references are much easier to work with than namespaces :wink: kudos!

3 Likes

Oh wow, that is very interesting. And I thought I was so clever finding my neat little trick.

Thank you for taking the time for such an elaborate reply, I’ll change it to the or-join now I know how to use it properly!

3 Likes