Hi folks!
I’m learning the query language and I wonder how to make a query with an optional exclusion.
So I need to get all the #note blocks that have TODO marker set, but exclude those which I’m currently working on in the current day in journal.
#+BEGIN_QUERY
{:title "🔨 TODO notes"
:query [:find (pull ?b [*])
:in $ ?today
:where
[?b :block/marker ?marker]
[(contains? #{"LATER" "TODO" "DOING"} ?marker)]
[?b :block/refs ?tag]
[?tag :block/name "note"]
[?b :block/page ?page]
[?page :block/journal? true]
[?page :block/journal-day ?date]
[(!= ?date ?today)]]
:inputs [:today]
:group-by-page? false
:collapsed? false
}
#+END_QUERY
In this query I constrain :block/page
to be journal. But I need to express:
if this block is in journal, then
apply the date condition
otherwise
ignore the date condition
How to do that?
UPD. I found a related thread: Query incomplete tasks which are not referenced from a specific page
I believe that approach is quite good: instead of checking the date, I can simply exclude blocks, that don’t belong to the current page - the journal day page.
In this case my condition changes to:
if this block belongs to the current page
exclude it
otherwise
include it
Try this:
(or-join [?today ?page]
(not [?page :block/journal? true])
(and
[?page :block/journal? true]
[?page :block/journal-day ?date]
[(!= ?date ?today)]
)
)
1 Like
I assume you just want to say:
- Don’t show tasks that are in current journal
We can just make it a “complete” not statement.
So:
(not
[?b :block/page ?page]
[?page :block/journal-day ?today]
)
It basically works like this:
- We create a subset which is #note TODO blocks that are on today’s journal page
- Then we say, from the whole set, subtract this subset
If that makes sense?
Edit, for clarity, the complete query is:
#+BEGIN_QUERY
{:title "🔨 TODO notes"
:query [:find (pull ?b [*])
:in $ ?today
:where
[?b :block/marker ?marker]
[(contains? #{"LATER" "TODO" "DOING"} ?marker)]
[?b :block/refs ?tag]
[?tag :block/name "note"]
(not
[?b :block/page ?page]
[?page :block/journal-day ?today]
)
]
:inputs [:today]
:group-by-page? false
:collapsed? false
}
#+END_QUERY
2 Likes
Maybe I did something wrong, but I get an error
Insufficient bindings: none of #{?page} is bound in (not [?page :block/journal? true])
with this query:
#+BEGIN_QUERY
{:title "🔨 TODO notes (mentaloid)"
:query [:find (pull ?b [*])
:in $ ?today
:where
[?b :block/marker ?marker]
(not [(contains? #{"DONE" "CANCELED" "CANCELLED"} ?marker)])
[?b :block/refs ?tag]
[?tag :block/name "note"]
(or-join [?today ?page]
(not [?page :block/journal? true])
(and
[?page :block/journal? true]
[?page :block/journal-day ?date]
[(!= ?date ?today)]
)
)
]
:inputs [:today]
}
#+END_QUERY
You removed this needed line:
[?b :block/page ?page]
1 Like
Thanks, it works exactly as I wished. And simple exclusion as you noticed is really what was required in this case
Exactly! Thank you!
Well, that answers my question how I phrased it.
Nice to see a solution using or-join
while I was thinking in SQL’s lef-joins
Difficult to pick the right solution as both solve my problem.
@Siferiax I like your solution more and will use it, but will pick the mentaloid’s answer as it literally answers my question.
1 Like
both are correct indeed.
My solution is more straightforward.
However, the one from mentaloid can be adapted to make a more complex query. For example the todo is not on a journal page, or on today’s journal page.
I think both have value.
2 Likes