How to show page title in table view mode by using advanced query

I want to fetch all pages that contains tag #inbox. I try query from https://docs.logseq.com/#/page/advanced%20queries

#+BEGIN_QUERY
{:title "All blocks with tag inbox"
   :query [:find (pull ?b [*])
         :where
         [?p :block/name "inbox"]
         [?b :block/refs ?p]]
 }
 #+END_QUERY

It works fine:

image

But in table view, i see only blocks:

image

How render only page titles in table view mode? I also see that the results in table / non-table view mode are sorted differently, how can I achieve the same sorting. Thanks in advance for your help.

1 Like

It seems like you have your tags in an indented sub-block and not in the same block as your todo.
Instead of

“Add lsp server to emacs
- [[inbox]]”

try it in one line

“Add lsp server to emacs [[inbox]]” or “[[inbox]] Add lsp server to emacs”.

Then your table view should show work.
Look at the advanced queries and find something like

:result-transform (fn [result]
(sort-by (fn [h]
(get h :block/created-at)) result))

and decide what your sorting should be.

1 Like

If i understand correctly you have a page that has a link to the page inbox and you want to grab that page and not the block which references inbox.
If so, here’s what you are looking for:

#+BEGIN_QUERY
{:title "All blocks with tag inbox"
   :query [:find (pull ?p [*])
         :where
         [?i :block/name "inbox"]
         [?b :block/refs ?i]
         [?b :block/page ?p]
  ]
 }
 #+END_QUERY
2 Likes

Same problem here.
Thanks @Siferiax . @Xardas solution outputs the blocks that link to “inbox”. Your solution outputs the pages linking to “inbox”. Is there a way to have best of both worlds? I.e. get all blocks, but with an additional table column “page title”, that shows, to which page each block belongs?

Yes, sort of :slight_smile:

#+BEGIN_QUERY
{:title "All blocks with tag inbox"
   :query [:find ?page ?id ?block
         :keys page id block
         :where
         [?i :block/name "inbox"]
         [?b :block/refs ?i]
         [?b :block/page ?p]
         [?b :block/uuid ?id]
         [?b :block/content ?block]
         [?p :block/original-name ?page]
  ]
   :view (fn [rows] [:table [:thead [:tr [:th "Page"] [:th "Block"] ] ]
   [:tbody (for [r rows] [:tr
     [:td [:a {:href (str "#/page/" (clojure.string/replace (get-in r [:page]) "/" "%2F"))}
 (get-in r [:page])] ]
     [:td [:a {:href (str "#/page/" (get-in r [:id]))} (get-in r [:block])] ]
    ])]
   ])
 }
 #+END_QUERY

image

4 Likes

Fantastic - thank you so much!

Out of curiosity, is there any way to get a bit more intuitive solution?

#+BEGIN_QUERY
{:title "All blocks with tag inbox"
   :query [:find (pull ?bp [*]) (pull ?b [*])
         :where
         [?p :block/name "inbox"]
         [?b :block/refs ?p]
         [?b :block/page ?bp]]
 }
 #+END_QUERY

only returns page data. Probably because page and block types are different?

#+BEGIN_QUERY
{:title "All blocks with tag inbox"
   :query [:find ?bp (pull ?b [*])
         :where
         [?p :block/name "inbox"]
         [?b :block/refs ?p]
         [?b :block/page ?bp]]
 }
 #+END_QUERY

returns raw data, but overall value seems right:

29{:block/uuid #uuid "63dbd362-...",
 :block/properties {},
 :block/left {:db/id 30},
 :block/refs [{:db/id 26}],
 :block/format :markdown,
 :block/content "block with link to [[inbox]]",
 :db/id 31,
 :block/path-refs [{:db/id 26} {:db/id 29}],
 :block/parent {:db/id 30},
 :block/page {:block/name "pb", :block/original-name "PB", :db/id 29}}

33{:block/uuid #uuid "63dbd36d-...",
 :block/properties {},
 :block/left {:db/id 34},
 :block/refs [{:db/id 26}],
 :block/format :markdown,
 :block/content "block with link to [[inbox]]",
 :db/id 35,
 :block/path-refs [{:db/id 26} {:db/id 33}],
 :block/parent {:db/id 34},
 :block/page {:block/name "pc", :block/original-name "PC", :db/id 33}}
1 Like

Yes, to turn that raw data into something more readable I made a custom table using :view.
The different return values get bound to keys (from the :find and :keys sections)
And then used in the :view to display them more nicely.
As you concluded correctly pages and blocks are different, most notable for this situation in their default result-transform and view used for :find (pull ?b [*]) (or ?p). Putting something different in :find will stop the default from working as intended and thus giving unexpected output.
At least that’s my interpretation.

2 Likes

@ste my goal is one page for each todo and first page block for status. You solution is nice, but I will have to duplicate the page title in the first block. @Siferiax you solution works perfect. Thanks guys.

1 Like

There’s an alternative way thanks to Darwis on discord:

Makes the query a bit more concise and allows for the default table view usage.
I took their example from discord and applied it to the query I made for this thread.

The query basically adds another property to the block so it can be used in the table view.

:journal is what is used as a name for page. Please be aware that :page is reserved and doesn’t work.

#+BEGIN_QUERY
{:title "All blocks with tag inbox"
   :query [:find (pull ?b [*])
         :where
         [?i :block/name "inbox"]
         [?b :block/refs ?i]
  ]
  :result-transform (fn [res] (sort-by (fn [s] (get-in s [:block/properties :journal-day])) > (map (fn [m] 
       (update m :block/properties 
           (fn [u] (assoc u :journal-day (get-in m [:block/page :block/journal-day]) :journal (get-in m [:block/page :block/name]))
           ))
    ) res)))
 }
 #+END_QUERY

PS. Also check out this feature request!

2 Likes