How to query todo without subtodos?

I want to catch from page TODO that has no sub todo

Example:

- TODO Task1
	- Description without marker
- TODO Task 2
	- Description
	- TODO subtask 2.1

in that case I should catch two rows:

  • Task1
  • subtask 2.1

So my current implementation is:

#+BEGIN_QUERY
{
:query [:find (pull ?block [* ])
:in $ ?current-page
:where
[?page :block/name ?current-page]
[?block :block/page ?page]
[?page :block/name ?pagename]
[?block :block/marker ?marker]
[(contains? #{"TODO"} ?marker)]
[?child :block/parent ?block]
[?child :block/marker ?childmarker]
(not [(contains? #{"TODO"} ?childmarker)])
]
:inputs [:current-page]
:view (fn [r] [:pre.code (pprint r)])
}
#+END_QUERY

But the query runs without returning rows

Welcome. Try this:

#+BEGIN_QUERY
{
 :query [:find (pull ?block [* ])
 :in $ ?current-page
 :where
   [?page :block/name ?current-page]      ; in current page
   [?block :block/page ?page]             ; any blocks
   [?block :block/marker ?marker]         ; that have marker
   [(contains? #{"TODO"} ?marker)]        ; TODO
   (not                                   ; but don't have
     [?child :block/parent ?block]        ; any child
     [?child :block/marker ?childmarker]  ; with own marker
     [(contains? #{"TODO"} ?childmarker)] ; TODO
   )
 ]
 :inputs [:current-page]
}
#+END_QUERY

Look like fine for now. Thanks!

In one test it failed, like:

- TODO Task1
	- Description without marker
- TODO Task 2
	- Description
	- TODO subtask 2.1
		- desc
			- TODO subtask 2.1.1
	- TODO subtask 2.2

it also will return subtask 2.1 but shouldn’t.

Can we search recursively?

We can, by using rules:

#+BEGIN_QUERY
{
 :query [:find (pull ?block [* ])
 :in $ ?current-page %
 :where
   [?page :block/name ?current-page]  ; in current page
   [?block :block/page ?page]         ; any blocks
   [?block :block/marker ?marker]     ; that have marker
   [(contains? #{"TODO"} ?marker)]    ; TODO
   (not                               ; but don't have
     (descendant ?d ?block)           ; any descendant
     [?d :block/marker ?dmarker]      ; with own marker
     [(contains? #{"TODO"} ?dmarker)] ; TODO
   )
 ]
 :inputs [
   :current-page
   [
     [
       [descendant ?d ?b]
       [?d :block/parent ?b]
     ]
     [
       [descendant ?d ?b]
       [?d :block/parent ?parent]
       (descendant ?parent ?b)
     ]
   ]
 ]
}
#+END_QUERY